/* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES
 * visit http://open62541.org/ for information about this software
 * Git-Revision: v1.5.5
 */

/*
 * Copyright (C) 2014-2021 the contributors as stated in the AUTHORS file
 *
 * This file is part of open62541. open62541 is free software: you can
 * redistribute it and/or modify it under the terms of the Mozilla Public
 * License v2.0 as stated in the LICENSE file provided with open62541.
 *
 * open62541 is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.
 */

#ifndef UA_DYNAMIC_LINKING_EXPORT
# define UA_DYNAMIC_LINKING_EXPORT
# define MDNSD_DYNAMIC_LINKING
#endif

#define UA_INLINABLE_IMPL 1

/* Disable security warnings for BSD sockets on MSVC */
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
#endif

#include "open62541.h"

/**** amalgamated original file "/deps/open62541_queue.h" ****/

/*	$OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $	*/
/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/

/*
 * Copyright (c) 1991, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)queue.h	8.5 (Berkeley) 8/20/94
 */


/*
 * This file defines five types of data structures: singly-linked lists, 
 * lists, simple queues, tail queues, and circular queues.
 *
 *
 * A singly-linked list is headed by a single forward pointer. The elements
 * are singly linked for minimum space and pointer manipulation overhead at
 * the expense of O(n) removal for arbitrary elements. New elements can be
 * added to the list after an existing element or at the head of the list.
 * Elements being removed from the head of the list should use the explicit
 * macro for this purpose for optimum efficiency. A singly-linked list may
 * only be traversed in the forward direction.  Singly-linked lists are ideal
 * for applications with large datasets and few or no removals or for
 * implementing a LIFO queue.
 *
 * A list is headed by a single forward pointer (or an array of forward
 * pointers for a hash table header). The elements are doubly linked
 * so that an arbitrary element can be removed without a need to
 * traverse the list. New elements can be added to the list before
 * or after an existing element or at the head of the list. A list
 * may only be traversed in the forward direction.
 *
 * A simple queue is headed by a pair of pointers, one the head of the
 * list and the other to the tail of the list. The elements are singly
 * linked to save space, so elements can only be removed from the
 * head of the list. New elements can be added to the list before or after
 * an existing element, at the head of the list, or at the end of the
 * list. A simple queue may only be traversed in the forward direction.
 *
 * A tail queue is headed by a pair of pointers, one to the head of the
 * list and the other to the tail of the list. The elements are doubly
 * linked so that an arbitrary element can be removed without a need to
 * traverse the list. New elements can be added to the list before or
 * after an existing element, at the head of the list, or at the end of
 * the list. A tail queue may be traversed in either direction.
 *
 * A circle queue is headed by a pair of pointers, one to the head of the
 * list and the other to the tail of the list. The elements are doubly
 * linked so that an arbitrary element can be removed without a need to
 * traverse the list. New elements can be added to the list before or after
 * an existing element, at the head of the list, or at the end of the list.
 * A circle queue may be traversed in either direction, but has a more
 * complex end of list detection.
 *
 * For details on the use of these macros, see the queue(3) manual page.
 */

#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif

/*
 * Singly-linked List definitions.
 */
#define SLIST_HEAD(name, type)						\
struct name {								\
    struct type *slh_first;	/* first element */			\
}
 
#define	SLIST_HEAD_INITIALIZER(head)					\
    { NULL }

#define SLIST_ENTRY(type)						\
struct {								\
    struct type *sle_next;	/* next element */			\
}
 
/*
 * Singly-linked List access methods.
 */
#define	SLIST_FIRST(head)	((head)->slh_first)
#define	SLIST_END(head)		NULL
#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)

#define	SLIST_FOREACH(var, head, field)					\
    for((var) = SLIST_FIRST(head);					\
        (var) != SLIST_END(head);					\
        (var) = SLIST_NEXT(var, field))

#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = SLIST_FIRST(head);				\
        (var) && ((tvar) = SLIST_NEXT(var, field), 1);		\
        (var) = (tvar))

/*
 * Singly-linked List functions.
 */
#define	SLIST_INIT(head) do {						\
    SLIST_FIRST(head) = SLIST_END(head);				\
} while(0)

#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
    (elm)->field.sle_next = (slistelm)->field.sle_next;		\
    (slistelm)->field.sle_next = (elm);				\
} while (0)

#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
    (elm)->field.sle_next = (head)->slh_first;			\
    (head)->slh_first = (elm);					\
} while (0)

#define	SLIST_REMOVE_AFTER(elm, field) do {				\
    (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
} while (0)

#define	SLIST_REMOVE_HEAD(head, field) do {				\
    (head)->slh_first = (head)->slh_first->field.sle_next;		\
} while (0)

#define SLIST_REMOVE(head, elm, type, field) do {			\
    if ((head)->slh_first == (elm)) {				\
        SLIST_REMOVE_HEAD((head), field);			\
    } else {							\
        struct type *curelm = (head)->slh_first;		\
                                    \
        while (curelm->field.sle_next != (elm))			\
            curelm = curelm->field.sle_next;		\
        curelm->field.sle_next =				\
            curelm->field.sle_next->field.sle_next;		\
        _Q_INVALIDATE((elm)->field.sle_next);			\
    }								\
} while (0)

/*
 * List definitions.
 */
#define LIST_HEAD(name, type)						\
struct name {								\
    struct type *lh_first;	/* first element */			\
}

#define LIST_HEAD_INITIALIZER(head)					\
    { NULL }

#define LIST_ENTRY(type)						\
struct {								\
    struct type *le_next;	/* next element */			\
    struct type **le_prev;	/* address of previous next element */	\
}

/*
 * List access methods
 */
#define	LIST_FIRST(head)		((head)->lh_first)
#define	LIST_END(head)			NULL
#define	LIST_EMPTY(head)		(LIST_FIRST(head) == LIST_END(head))
#define	LIST_NEXT(elm, field)		((elm)->field.le_next)

#define LIST_FOREACH(var, head, field)					\
    for((var) = LIST_FIRST(head);					\
        (var)!= LIST_END(head);					\
        (var) = LIST_NEXT(var, field))

#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = LIST_FIRST(head);				\
        (var) && ((tvar) = LIST_NEXT(var, field), 1);		\
        (var) = (tvar))

/*
 * List functions.
 */
#define	LIST_INIT(head) do {						\
    LIST_FIRST(head) = LIST_END(head);				\
} while (0)

#define LIST_INSERT_AFTER(listelm, elm, field) do {			\
    if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
        (listelm)->field.le_next->field.le_prev =		\
            &(elm)->field.le_next;				\
    (listelm)->field.le_next = (elm);				\
    (elm)->field.le_prev = &(listelm)->field.le_next;		\
} while (0)

#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
    (elm)->field.le_prev = (listelm)->field.le_prev;		\
    (elm)->field.le_next = (listelm);				\
    *(listelm)->field.le_prev = (elm);				\
    (listelm)->field.le_prev = &(elm)->field.le_next;		\
} while (0)

#define LIST_INSERT_HEAD(head, elm, field) do {				\
    if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
        (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
    (head)->lh_first = (elm);					\
    (elm)->field.le_prev = &(head)->lh_first;			\
} while (0)

#define LIST_REMOVE(elm, field) do {					\
    if ((elm)->field.le_next != NULL)				\
        (elm)->field.le_next->field.le_prev =			\
            (elm)->field.le_prev;				\
    *(elm)->field.le_prev = (elm)->field.le_next;			\
    _Q_INVALIDATE((elm)->field.le_prev);				\
    _Q_INVALIDATE((elm)->field.le_next);				\
} while (0)

#define LIST_REPLACE(elm, elm2, field) do {				\
    if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
        (elm2)->field.le_next->field.le_prev =			\
            &(elm2)->field.le_next;				\
    (elm2)->field.le_prev = (elm)->field.le_prev;			\
    *(elm2)->field.le_prev = (elm2);				\
    _Q_INVALIDATE((elm)->field.le_prev);				\
    _Q_INVALIDATE((elm)->field.le_next);				\
} while (0)

/*
 * Simple queue definitions.
 */
#define SIMPLEQ_HEAD(name, type)					\
struct name {								\
    struct type *sqh_first;	/* first element */			\
    struct type **sqh_last;	/* addr of last next element */		\
}

#define SIMPLEQ_HEAD_INITIALIZER(head)					\
    { NULL, &(head).sqh_first }

#define SIMPLEQ_ENTRY(type)						\
struct {								\
    struct type *sqe_next;	/* next element */			\
}

/*
 * Simple queue access methods.
 */
#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
#define	SIMPLEQ_END(head)	    NULL
#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)

#define SIMPLEQ_FOREACH(var, head, field)				\
    for((var) = SIMPLEQ_FIRST(head);				\
        (var) != SIMPLEQ_END(head);					\
        (var) = SIMPLEQ_NEXT(var, field))

#define	SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = SIMPLEQ_FIRST(head);				\
        (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1);		\
        (var) = (tvar))

/*
 * Simple queue functions.
 */
#define	SIMPLEQ_INIT(head) do {						\
    (head)->sqh_first = NULL;					\
    (head)->sqh_last = &(head)->sqh_first;				\
} while (0)

#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
    if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
        (head)->sqh_last = &(elm)->field.sqe_next;		\
    (head)->sqh_first = (elm);					\
} while (0)

#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.sqe_next = NULL;					\
    *(head)->sqh_last = (elm);					\
    (head)->sqh_last = &(elm)->field.sqe_next;			\
} while (0)

#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
        (head)->sqh_last = &(elm)->field.sqe_next;		\
    (listelm)->field.sqe_next = (elm);				\
} while (0)

#define SIMPLEQ_REMOVE_HEAD(head, field) do {			\
    if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
        (head)->sqh_last = &(head)->sqh_first;			\
} while (0)

#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
    if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
        == NULL)							\
        (head)->sqh_last = &(elm)->field.sqe_next;		\
} while (0)

/*
 * XOR Simple queue definitions.
 */
#define XSIMPLEQ_HEAD(name, type)					\
struct name {								\
    struct type *sqx_first;	/* first element */			\
    struct type **sqx_last;	/* addr of last next element */		\
    unsigned long sqx_cookie;					\
}

#define XSIMPLEQ_ENTRY(type)						\
struct {								\
    struct type *sqx_next;	/* next element */			\
}

/*
 * XOR Simple queue access methods.
 */
#define XSIMPLEQ_XOR(head, ptr)	    ((__typeof(ptr))((head)->sqx_cookie ^ \
                    (unsigned long)(ptr)))
#define	XSIMPLEQ_FIRST(head)	    XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define	XSIMPLEQ_END(head)	    NULL
#define	XSIMPLEQ_EMPTY(head)	    (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define	XSIMPLEQ_NEXT(head, elm, field)    XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))


#define XSIMPLEQ_FOREACH(var, head, field)				\
    for ((var) = XSIMPLEQ_FIRST(head);				\
        (var) != XSIMPLEQ_END(head);				\
        (var) = XSIMPLEQ_NEXT(head, var, field))

#define	XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = XSIMPLEQ_FIRST(head);				\
        (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1);	\
        (var) = (tvar))

/*
 * XOR Simple queue functions.
 */
#define	XSIMPLEQ_INIT(head) do {					\
    arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
    (head)->sqx_first = XSIMPLEQ_XOR(head, NULL);			\
    (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first);	\
} while (0)

#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
    if (((elm)->field.sqx_next = (head)->sqx_first) ==		\
        XSIMPLEQ_XOR(head, NULL))					\
        (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
    (head)->sqx_first = XSIMPLEQ_XOR(head, (elm));			\
} while (0)

#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL);		\
    *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
    (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);	\
} while (0)

#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    if (((elm)->field.sqx_next = (listelm)->field.sqx_next) ==	\
        XSIMPLEQ_XOR(head, NULL))					\
        (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
    (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm));		\
} while (0)

#define XSIMPLEQ_REMOVE_HEAD(head, field) do {				\
    if (((head)->sqx_first = XSIMPLEQ_XOR(head,			\
        (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
        (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)

#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
    if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head,			\
        (elm)->field.sqx_next)->field.sqx_next)			\
        == XSIMPLEQ_XOR(head, NULL))				\
        (head)->sqx_last = 					\
            XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);		\
} while (0)

            
/*
 * Tail queue definitions.
 */
#define TAILQ_HEAD(name, type)						\
struct name {								\
    struct type *tqh_first;	/* first element */			\
    struct type **tqh_last;	/* addr of last next element */		\
}

#define TAILQ_HEAD_INITIALIZER(head)					\
    { NULL, &(head).tqh_first }

#define TAILQ_ENTRY(type)						\
struct {								\
    struct type *tqe_next;	/* next element */			\
    struct type **tqe_prev;	/* address of previous next element */	\
}

/* 
 * tail queue access methods 
 */
#define	TAILQ_FIRST(head)		((head)->tqh_first)
#define	TAILQ_END(head)			NULL
#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname)					\
    (*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field)				\
    (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define	TAILQ_EMPTY(head)						\
    (TAILQ_FIRST(head) == TAILQ_END(head))

#define TAILQ_FOREACH(var, head, field)					\
    for((var) = TAILQ_FIRST(head);					\
        (var) != TAILQ_END(head);					\
        (var) = TAILQ_NEXT(var, field))

#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = TAILQ_FIRST(head);					\
        (var) != TAILQ_END(head) &&					\
        ((tvar) = TAILQ_NEXT(var, field), 1);			\
        (var) = (tvar))


#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
    for((var) = TAILQ_LAST(head, headname);				\
        (var) != TAILQ_END(head);					\
        (var) = TAILQ_PREV(var, headname, field))

#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
    for ((var) = TAILQ_LAST(head, headname);			\
        (var) != TAILQ_END(head) &&					\
        ((tvar) = TAILQ_PREV(var, headname, field), 1);		\
        (var) = (tvar))

/*
 * Tail queue functions.
 */
#define	TAILQ_INIT(head) do {						\
    (head)->tqh_first = NULL;					\
    (head)->tqh_last = &(head)->tqh_first;				\
} while (0)

#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
    if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
        (head)->tqh_first->field.tqe_prev =			\
            &(elm)->field.tqe_next;				\
    else								\
        (head)->tqh_last = &(elm)->field.tqe_next;		\
    (head)->tqh_first = (elm);					\
    (elm)->field.tqe_prev = &(head)->tqh_first;			\
} while (0)

#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.tqe_next = NULL;					\
    (elm)->field.tqe_prev = (head)->tqh_last;			\
    *(head)->tqh_last = (elm);					\
    (head)->tqh_last = &(elm)->field.tqe_next;			\
} while (0)

#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
        (elm)->field.tqe_next->field.tqe_prev =			\
            &(elm)->field.tqe_next;				\
    else								\
        (head)->tqh_last = &(elm)->field.tqe_next;		\
    (listelm)->field.tqe_next = (elm);				\
    (elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
} while (0)

#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
    (elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
    (elm)->field.tqe_next = (listelm);				\
    *(listelm)->field.tqe_prev = (elm);				\
    (listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
} while (0)

#define TAILQ_REMOVE(head, elm, field) do {				\
    if (((elm)->field.tqe_next) != NULL)				\
        (elm)->field.tqe_next->field.tqe_prev =			\
            (elm)->field.tqe_prev;				\
    else								\
        (head)->tqh_last = (elm)->field.tqe_prev;		\
    *(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
    _Q_INVALIDATE((elm)->field.tqe_prev);				\
    _Q_INVALIDATE((elm)->field.tqe_next);				\
} while (0)

#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
    if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
        (elm2)->field.tqe_next->field.tqe_prev =		\
            &(elm2)->field.tqe_next;				\
    else								\
        (head)->tqh_last = &(elm2)->field.tqe_next;		\
    (elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
    *(elm2)->field.tqe_prev = (elm2);				\
    _Q_INVALIDATE((elm)->field.tqe_prev);				\
    _Q_INVALIDATE((elm)->field.tqe_next);				\
} while (0)

/*
 * Circular queue definitions.
 */
#define CIRCLEQ_HEAD(name, type)					\
struct name {								\
    struct type *cqh_first;		/* first element */		\
    struct type *cqh_last;		/* last element */		\
}

#define CIRCLEQ_HEAD_INITIALIZER(head)					\
    { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }

#define CIRCLEQ_ENTRY(type)						\
struct {								\
    struct type *cqe_next;		/* next element */		\
    struct type *cqe_prev;		/* previous element */		\
}

/*
 * Circular queue access methods 
 */
#define	CIRCLEQ_FIRST(head)		((head)->cqh_first)
#define	CIRCLEQ_LAST(head)		((head)->cqh_last)
#define	CIRCLEQ_END(head)		((void *)(head))
#define	CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
#define	CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
#define	CIRCLEQ_EMPTY(head)						\
    (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))

#define CIRCLEQ_FOREACH(var, head, field)				\
    for((var) = CIRCLEQ_FIRST(head);				\
        (var) != CIRCLEQ_END(head);					\
        (var) = CIRCLEQ_NEXT(var, field))

#define	CIRCLEQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = CIRCLEQ_FIRST(head);				\
        (var) != CIRCLEQ_END(head) &&				\
        ((tvar) = CIRCLEQ_NEXT(var, field), 1);			\
        (var) = (tvar))

#define CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
    for((var) = CIRCLEQ_LAST(head);					\
        (var) != CIRCLEQ_END(head);					\
        (var) = CIRCLEQ_PREV(var, field))

#define	CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
    for ((var) = CIRCLEQ_LAST(head, headname);			\
        (var) != CIRCLEQ_END(head) && 				\
        ((tvar) = CIRCLEQ_PREV(var, headname, field), 1);		\
        (var) = (tvar))

/*
 * Circular queue functions.
 */
#define	CIRCLEQ_INIT(head) do {						\
    (head)->cqh_first = CIRCLEQ_END(head);				\
    (head)->cqh_last = CIRCLEQ_END(head);				\
} while (0)

#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    (elm)->field.cqe_next = (listelm)->field.cqe_next;		\
    (elm)->field.cqe_prev = (listelm);				\
    if ((listelm)->field.cqe_next == CIRCLEQ_END(head))		\
        (head)->cqh_last = (elm);				\
    else								\
        (listelm)->field.cqe_next->field.cqe_prev = (elm);	\
    (listelm)->field.cqe_next = (elm);				\
} while (0)

#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
    (elm)->field.cqe_next = (listelm);				\
    (elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
    if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))		\
        (head)->cqh_first = (elm);				\
    else								\
        (listelm)->field.cqe_prev->field.cqe_next = (elm);	\
    (listelm)->field.cqe_prev = (elm);				\
} while (0)

#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
    (elm)->field.cqe_next = (head)->cqh_first;			\
    (elm)->field.cqe_prev = CIRCLEQ_END(head);			\
    if ((head)->cqh_last == CIRCLEQ_END(head))			\
        (head)->cqh_last = (elm);				\
    else								\
        (head)->cqh_first->field.cqe_prev = (elm);		\
    (head)->cqh_first = (elm);					\
} while (0)

#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.cqe_next = CIRCLEQ_END(head);			\
    (elm)->field.cqe_prev = (head)->cqh_last;			\
    if ((head)->cqh_first == CIRCLEQ_END(head))			\
        (head)->cqh_first = (elm);				\
    else								\
        (head)->cqh_last->field.cqe_next = (elm);		\
    (head)->cqh_last = (elm);					\
} while (0)

#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
    if ((elm)->field.cqe_next == CIRCLEQ_END(head))			\
        (head)->cqh_last = (elm)->field.cqe_prev;		\
    else								\
        (elm)->field.cqe_next->field.cqe_prev =			\
            (elm)->field.cqe_prev;				\
    if ((elm)->field.cqe_prev == CIRCLEQ_END(head))			\
        (head)->cqh_first = (elm)->field.cqe_next;		\
    else								\
        (elm)->field.cqe_prev->field.cqe_next =			\
            (elm)->field.cqe_next;				\
    _Q_INVALIDATE((elm)->field.cqe_prev);				\
    _Q_INVALIDATE((elm)->field.cqe_next);				\
} while (0)

#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {			\
    if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==		\
        CIRCLEQ_END(head))						\
        (head)->cqh_last = (elm2);				\
    else								\
        (elm2)->field.cqe_next->field.cqe_prev = (elm2);	\
    if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==		\
        CIRCLEQ_END(head))						\
        (head)->cqh_first = (elm2);				\
    else								\
        (elm2)->field.cqe_prev->field.cqe_next = (elm2);	\
    _Q_INVALIDATE((elm)->field.cqe_prev);				\
    _Q_INVALIDATE((elm)->field.cqe_next);				\
} while (0)


/**** amalgamated original file "/deps/pcg_basic.h" ****/

/*
 * PCG Random Number Generation for C.
 *
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *     http://www.pcg-random.org
 */


#if defined(UNDER_CE) || !defined(_MSC_VER) || _MSC_VER >= 1800
# include <stdint.h>
#else
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct pcg_state_setseq_64 {
    uint64_t state;  /* RNG state.  All values are possible. */
    uint64_t inc;    /* Controls which RNG sequence (stream) is selected. Must
                      * *always* be odd. */
} pcg32_random_t;

#define PCG32_INITIALIZER { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }

void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq);
uint32_t pcg32_random_r(pcg32_random_t* rng);

#ifdef __cplusplus
}
#endif


/**** amalgamated original file "/deps/libc_time.h" ****/


struct musl_tm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    /* int tm_isdst; */
    /* long __tm_gmtoff; */
    /* const char *__tm_zone; */
};

int musl_secs_to_tm(long long t, struct musl_tm *tm);
long long musl_tm_to_secs(const struct musl_tm *tm);


/**** amalgamated original file "/deps/base64.h" ****/

#ifndef UA_BASE64_H_
#define UA_BASE64_H_


_UA_BEGIN_DECLS

#include <stddef.h>

/**
 * base64_encode - Base64 encode
 * @src: Data to be encoded
 * @len: Length of the data to be encoded
 * @out_len: Pointer to output length variable
 * Returns: Allocated buffer of out_len bytes of encoded data,
 * or %NULL on failure. The output is NOT Null-terminated. */
unsigned char *
UA_base64(const unsigned char *src, size_t len, size_t *out_len);

/* Requires as input a buffer of length at least 4*((len + 2) / 3).
 * Returns the actual size */
size_t
UA_base64_buf(const unsigned char *src, size_t len, unsigned char *out);

/**
 * base64_decode - Base64 decode. The input can also be a base64url (with -_
 * instead of +/ and no = for padding).
 *
 * @src: Data to be decoded
 * @len: Length of the data to be decoded
 * @out_len: Pointer to output length variable
 * Returns: Allocated buffer of out_len bytes of decoded data,
 * or %NULL on failure. */
unsigned char *
UA_unbase64(const unsigned char *src, size_t len, size_t *out_len);

_UA_END_DECLS

#endif /* UA_BASE64_H_ */

/**** amalgamated original file "/deps/dtoa.h" ****/

// Copyright 2013, Andreas Samoljuk
// Copyright 2023, Julius Pfrommer
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#ifndef DTOA_H
#define DTOA_H

#ifdef __cplusplus
extern "C" {
#endif

// Prints a double-value as a readable string. The buffer must be at least 24
// chars wide. Returns the number of printed characters. Does not
// null-terminate.
unsigned dtoa(double d, char* buffer);

#ifdef __cplusplus
}
#endif

#endif // DTOA_H

/**** amalgamated original file "/deps/musl_inet_pton.h" ****/

/* musl as a whole is licensed under the following standard MIT license:
*
 * ----------------------------------------------------------------------
 * Copyright © 2005-2020 Rich Felker, et al.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *----------------------------------------------------------------------
 */

#ifndef MUSL_INET_PTON_H
#define MUSL_INET_PTON_H


#if defined(UA_ARCHITECTURE_WIN32)
#include <winsock2.h>     /* AF_INET */
#elif defined(UA_ARCHITECTURE_LWIP)
#include <lwip/sockets.h> /* AF_INET */
#else
#include <sys/socket.h>   /* AF_INET */
#endif

int musl_inet_pton(int af, const char * UA_RESTRICT s, void * UA_RESTRICT a0);

#endif /* MUSL_INET_PTON_H */

/**** amalgamated original file "/deps/mp_printf.h" ****/

/**
 * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
 *             2021-2023, Haifa, Palestine/Israel
 * @author (c) Marco Paland (info@paland.com)
 *             2014-2019, PALANDesign Hannover, Germany
 *
 * @note Others have made smaller contributions to this file: see the
 * contributors page at https://github.com/eyalroz/printf/graphs/contributors
 * or ask one of the authors.
 *
 * @brief Small stand-alone implementation of the printf family of functions
 * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
 * a very limited resources.
 *
 * @note the implementations are thread-safe; re-entrant; use no functions from
 * the standard library; and do not dynamically allocate any memory.
 *
 * @license The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef MP_PRINTF_H
#define MP_PRINTF_H

#include <stdarg.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * An implementation of the C standard's snprintf/vsnprintf
 *
 * This is extended for the open62541 project to take some OPC UA datatypes
 * directly with the following format specifiers:
 *
 * %S - UA_String (without wrapping in quotation marks)
 * %N - UA_NodeId (using UA_NodeId_print)
 * %Q - UA_QualifiedName (using UA_QualifiedName_print)
 *
 * @param s An array in which to store the formatted string. It must be large
 * enough to fit either the entire formatted output, or at least @p n
 * characters. Alternatively, it can be NULL, in which case nothing will be
 * printed, and only the number of characters which _could_ have been printed is
 * tallied and returned.
 * @param count The maximum number of characters to write to the array, including a
 * terminating null character
 * @param format A string specifying the format of the output, with %-marked
 * specifiers of how to interpret additional arguments.
 * @param arg Additional arguments to the function, one for each specifier in @p
 * format
 * @return The number of characters that COULD have been written into @p s, not
 * counting the terminating null character. A value equal or larger than @p n
 * indicates truncation. Only when the returned value is non-negative and less
 * than @p n, the null-terminated string has been fully and successfully
 * printed.
 */
int mp_vsnprintf(char* s, size_t count, const char* format, va_list arg);
int  mp_snprintf(char* s, size_t count, const char* format, ...);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // MP_PRINTF_H

/**** amalgamated original file "/deps/utf8.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */

#ifndef UTF8_H_
#define UTF8_H_

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _MSC_VER
# define UTF_INLINE __inline
#else
# define UTF_INLINE inline
#endif

#if defined(__GNUC__) || defined(__clang__)
# define UTF_LIKELY(x) __builtin_expect((x), 1)
# define UTF_UNLIKELY(x) __builtin_expect((x), 0)
#else
# define UTF_LIKELY(x) (x)
# define UTF_UNLIKELY(x) (x)
#endif

/* Extract the next utf8 codepoint from the buffer. Returns the length (1-4) of
 * the codepoint encoding or 0 upon an error. */
unsigned
utf8_to_codepoint(const unsigned char *str, size_t len, unsigned *codepoint);

/* Encodes the codepoint in utf8. The string needs to have enough space (at most
 * four byte) available. Returns the encoding length. */
static UTF_INLINE unsigned
utf8_from_codepoint(unsigned char *str, unsigned codepoint) {
    if(UTF_LIKELY(codepoint <= 0x7F)) { /* Plain ASCII */
        str[0] = (unsigned char)codepoint;
        return 1;
    }
    if(UTF_LIKELY(codepoint <= 0x07FF)) { /* 2-byte unicode */
        str[0] = (unsigned char)(((codepoint >> 6) & 0x1F) | 0xC0);
        str[1] = (unsigned char)(((codepoint >> 0) & 0x3F) | 0x80);
        return 2;
    }
    if(UTF_LIKELY(codepoint <= 0xFFFF)) { /* 3-byte unicode */
        str[0] = (unsigned char)(((codepoint >> 12) & 0x0F) | 0xE0);
        str[1] = (unsigned char)(((codepoint >>  6) & 0x3F) | 0x80);
        str[2] = (unsigned char)(((codepoint >>  0) & 0x3F) | 0x80);
        return 3;
    }
    if(UTF_LIKELY(codepoint <= 0x10FFFF)) { /* 4-byte unicode */
        str[0] = (unsigned char)(((codepoint >> 18) & 0x07) | 0xF0);
        str[1] = (unsigned char)(((codepoint >> 12) & 0x3F) | 0x80);
        str[2] = (unsigned char)(((codepoint >>  6) & 0x3F) | 0x80);
        str[3] = (unsigned char)(((codepoint >>  0) & 0x3F) | 0x80);
        return 4;
    }
    return 0; /* Not a unicode codepoint */
}

/* Returns the encoding length of the codepoint */
static UTF_INLINE unsigned
utf8_length(unsigned codepoint) {
    if(UTF_LIKELY(codepoint <= 0x7F))
        return 1; /* Plain ASCII */
    if(UTF_LIKELY(codepoint <= 0x07FF))
        return 2; /* 2-byte unicode */
    if(UTF_LIKELY(codepoint <= 0xFFFF))
        return 3; /* 3-byte unicode */
    if(UTF_LIKELY(codepoint <= 0x10FFFF))
        return 4; /* 4-byte unicode */
    return 0; /* Not a unicode codepoint */
}

#ifdef __cplusplus
}
#endif

#endif /* UTF8_H_ */

/**** amalgamated original file "/deps/itoa.h" ****/

/*
 * Copyright 2017 Techie Delight
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef ITOA_H
#define ITOA_H

#ifdef __cplusplus
extern "C" {
#endif


UA_UInt16 itoaUnsigned(UA_UInt64 value, char* buffer, UA_Byte base);
UA_UInt16 itoaSigned(UA_Int64 value, char* buffer);

#ifdef __cplusplus
}
#endif

#endif /* ITOA_H */


/**** amalgamated original file "/deps/ziptree.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 *
 *    Copyright 2018, 2021-2022 (c) Julius Pfrommer
 */


#include <stddef.h>

#ifdef _MSC_VER
# define ZIP_INLINE __inline
#else
# define ZIP_INLINE inline
#endif

#if defined(__GNUC__) || defined(__clang__)
# define ZIP_UNUSED __attribute__((unused))
#else
# define ZIP_UNUSED
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* Reusable zip tree implementation. The style is inspired by the BSD
 * sys/queue.h linked list definition.
 *
 * Zip trees were developed in: Tarjan, R. E., Levy, C. C., and Timmel, S. "Zip
 * Trees." arXiv preprint arXiv:1806.06726 (2018). The original definition was
 * modified in two ways:
 *
 * - Multiple elements with the same key can be inserted. These appear adjacent
 *   in the tree. ZIP_FIND will return the topmost of these elements.
 * - The pointer-value of the elements are used as the rank. This simplifies the
 *   code and is (empirically) faster.
 *
 * The ZIP_ENTRY definitions are to be contained in the tree entries themselves.
 * Use ZIP_FUNCTIONS to define the signature of the zip tree functions. */

#define ZIP_HEAD(name, type)                    \
struct name {                                   \
    struct type *root;                          \
}

#define ZIP_ENTRY(type)                         \
struct {                                        \
    struct type *left;                          \
    struct type *right;                         \
}

enum ZIP_CMP {
    ZIP_CMP_LESS = -1,
    ZIP_CMP_EQ = 0,
    ZIP_CMP_MORE = 1
};

/* The comparison method "cmp" for a zip tree has the signature.
 * Provide this to the ZIP_FUNCTIONS macro.
 *
 *   enum ZIP_CMP cmpMethod(const keytype *a, const keytype *b);
 */
typedef enum ZIP_CMP (*zip_cmp_cb)(const void *key1, const void *key2);

#define ZIP_INIT(head) do { (head)->root = NULL; } while (0)
#define ZIP_ROOT(head) (head)->root
#define ZIP_LEFT(elm, field) (elm)->field.left
#define ZIP_RIGHT(elm, field) (elm)->field.right
#define ZIP_INSERT(name, head, elm) name##_ZIP_INSERT(head, elm)
#define ZIP_FIND(name, head, key) name##_ZIP_FIND(head, key)
#define ZIP_MIN(name, head) name##_ZIP_MIN(head)
#define ZIP_MAX(name, head) name##_ZIP_MAX(head)

/* Returns the element if it was found in the tree. Returns NULL otherwise. */
#define ZIP_REMOVE(name, head, elm) name##_ZIP_REMOVE(head, elm)

/* Split (_UNZIP) and merge (_ZIP) trees. _UNZIP splits at the key and moves
 * elements <= into the left output (right otherwise). */
#define ZIP_ZIP(name, left, right) name##_ZIP_ZIP(left, right)
#define ZIP_UNZIP(name, head, key, left, right) \
    name##_ZIP_UNZIP(head, key, left, right)

/* ZIP_ITER uses in-order traversal of the tree (in the order of the keys). The
 * memory if a node is not accessed by ZIP_ITER after the callback has been
 * executed for it. So a tree can be cleaned by calling free on each node from
 * within the iteration callback.
 *
 * ZIP_ITER returns a void pointer. The first callback to return non-NULL aborts
 * the iteration. This pointer is then returned. */
typedef void * (*zip_iter_cb)(void *context, void *elm);
#define ZIP_ITER(name, head, cb, ctx) name##_ZIP_ITER(head, cb, ctx)

/* Same as _ITER, but only visits elements with the given key */
#define ZIP_ITER_KEY(name, head, key, cb, ctx) name##_ZIP_ITER_KEY(head, key, cb, ctx)

/* Macro to generate typed ziptree methods */
#define ZIP_FUNCTIONS(name, type, field, keytype, keyfield, cmp)        \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void                                       \
name##_ZIP_INSERT(struct name *head, struct type *el) {                 \
    __ZIP_INSERT(head, (zip_cmp_cb)cmp, offsetof(struct type, field),   \
                 offsetof(struct type, keyfield), el);                  \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_REMOVE(struct name *head, struct type *elm) {                \
    return (struct type*)                                               \
        __ZIP_REMOVE(head, (zip_cmp_cb)cmp,                             \
                     offsetof(struct type, field),                      \
                     offsetof(struct type, keyfield), elm);             \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_FIND(struct name *head, const keytype *key) {                \
    struct type *cur = ZIP_ROOT(head);                                  \
    while(cur) {                                                        \
        enum ZIP_CMP eq = cmp(key, &cur->keyfield);                     \
        if(eq == ZIP_CMP_EQ)                                            \
            break;                                                      \
        if(eq == ZIP_CMP_LESS)                                          \
            cur = ZIP_LEFT(cur, field);                                 \
        else                                                            \
            cur = ZIP_RIGHT(cur, field);                                \
    }                                                                   \
    return cur;                                                         \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_MIN(struct name *head) {                                     \
    struct type *cur = ZIP_ROOT(head);                                  \
    if(!cur)                                                            \
        return NULL;                                                    \
    while(ZIP_LEFT(cur, field)) {                                       \
        cur = ZIP_LEFT(cur, field);                                     \
    }                                                                   \
    return cur;                                                         \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_MAX(struct name *head) {                                     \
    struct type *cur = ZIP_ROOT(head);                                  \
    if(!cur)                                                            \
        return NULL;                                                    \
    while(ZIP_RIGHT(cur, field)) {                                      \
        cur = ZIP_RIGHT(cur, field);                                    \
    }                                                                   \
    return cur;                                                         \
}                                                                       \
                                                                        \
typedef void * (*name##_cb)(void *context, struct type *elm);           \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void *                                     \
name##_ZIP_ITER(struct name *head, name##_cb cb, void *context) {       \
    return __ZIP_ITER(offsetof(struct type, field), (zip_iter_cb)cb,    \
                      context, ZIP_ROOT(head));                         \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void *                                     \
name##_ZIP_ITER_KEY(struct name *head, const keytype *key,              \
                    name##_cb cb, void *context) {                      \
    return __ZIP_ITER_KEY((zip_cmp_cb)cmp, offsetof(struct type, field), \
                          offsetof(struct type, keyfield), key,         \
                          (zip_iter_cb)cb, context, ZIP_ROOT(head));    \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_ZIP(struct type *left, struct type *right) {                 \
    return (struct type*)                                               \
        __ZIP_ZIP(offsetof(struct type, field), left, right);           \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void                                       \
name##_ZIP_UNZIP(struct name *head, const keytype *key,                 \
                 struct name *left, struct name *right) {               \
    __ZIP_UNZIP((zip_cmp_cb)cmp, offsetof(struct type, field),          \
                offsetof(struct type, keyfield), key,                   \
                head, left, right);                                     \
}

/* Internal definitions. Don't use directly. */

void
__ZIP_INSERT(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm);

void *
__ZIP_REMOVE(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm);

void *
__ZIP_ITER(unsigned short fieldoffset, zip_iter_cb cb,
           void *context, void *elm);

void *
__ZIP_ITER_KEY(zip_cmp_cb cmp, unsigned short fieldoffset,
               unsigned short keyoffset, const void *key,
               zip_iter_cb cb, void *context, void *elm);

void *
__ZIP_ZIP(unsigned short fieldoffset, void *left, void *right);

void
__ZIP_UNZIP(zip_cmp_cb cmp, unsigned short fieldoffset,
            unsigned short keyoffset, const void *key,
            void *h, void *l, void *r);

#ifdef __cplusplus
} /* extern "C" */
#endif


/**** amalgamated original file "/deps/parse_num.h" ****/

#ifndef ATOI_H
#define ATOI_H

#ifdef __cplusplus
extern "C" {
#endif

#if !defined(_MSC_VER) || _MSC_VER >= 1800
# include <stddef.h>
# include <stdint.h>
# include <stdbool.h> /* C99 Boolean */
#else
# if !defined(__bool_true_false_are_defined)
#  define bool unsigned char
#  define true 1
#  define false 0
#  define __bool_true_false_are_defined
# endif
#endif

/* Parse integer numbers. Returns the number of parsed digits until the first
 * non-valid character. Returns 0 upon failure.
 *
 * Hex numbers start with 0x.
 * Signed numbers may have a +/- prefix. */

size_t parseUInt64(const char *str, size_t size, uint64_t *result);
size_t parseInt64(const char *str, size_t size, int64_t *result);
size_t parseDouble(const char *str, size_t size, double *result);
    
#ifdef __cplusplus
}
#endif

#endif /* ATOI_H */


/**** amalgamated original file "/src/ua_types_encoding_binary.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Sten Grüner
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 */



_UA_BEGIN_DECLS

typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos,
                                                 const UA_Byte **bufEnd);

typedef struct {
    /* Pointers to the current and last buffer position */
    UA_Byte *pos;
    const UA_Byte *end;

    /* How often did we en-/decoding recurse? */
    UA_Byte depth;

    UA_DecodeBinaryOptions opts;

    UA_exchangeEncodeBuffer exchangeBufferCallback;
    void *exchangeBufferCallbackHandle;
} Ctx;

void * ctxCalloc(Ctx *ctx, size_t nelem, size_t elsize);
void ctxFree(Ctx *ctx, void *p);
void ctxClear(Ctx *ctx, void *p, const UA_DataType *type);

/* Jumptables for de-/encoding and computing the buffer length. The methods in
 * the decoding jumptable do not memset-zero initially and do not clean up their
 * allocated memory when an error occurs. So a final _clear needs to be called
 * before returning to the user. */
typedef UA_StatusCode
(*encodeBinarySignature)(Ctx *UA_RESTRICT ctx, const void *UA_RESTRICT src,
                         const UA_DataType *type);
typedef UA_StatusCode
(*decodeBinarySignature)(Ctx *UA_RESTRICT ctx, void *UA_RESTRICT dst,
                         const UA_DataType *type);
extern const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS];
extern const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS];

#define DECODE_BINARY(VAR, TYPE)                                    \
    decodeBinaryJumpTable[UA_DATATYPEKIND_##TYPE](ctx, VAR, NULL);

#define ENCODE_BINARY(VAR, TYPE)                                    \
    encodeBinaryJumpTable[UA_DATATYPEKIND_##TYPE](ctx, VAR, NULL);

/* Encodes the scalar value described by type in the binary encoding. Encoding
 * is thread-safe if thread-local variables are enabled. Encoding is also
 * reentrant and can be safely called from signal handlers or interrupts.
 *
 * @param src The value. Must not be NULL.
 * @param type The value type. Must not be NULL.
 * @param bufPos Points to a pointer to the current position in the encoding
 *        buffer. Must not be NULL. The pointer is advanced by the number of
 *        encoded bytes, or, if the buffer is exchanged, to the position in the
 *        new buffer.
 * @param bufEnd Points to a pointer to the end of the encoding buffer (encoding
 *        always stops before *buf_end). Must not be NULL. The pointer is
 *        changed when the buffer is exchanged.
 * @param exchangeCallback Called when the end of the buffer is reached. This is
          used to send out a message chunk before continuing with the encoding.
          Is ignored if NULL.
 * @param exchangeHandle Custom data passed into the exchangeCallback.
 * @return Returns a statuscode whether encoding succeeded. */
UA_StatusCode
UA_encodeBinaryInternal(const void *src, const UA_DataType *type,
                        UA_Byte **bufPos, const UA_Byte **bufEnd,
                        UA_EncodeBinaryOptions *options,
                        UA_exchangeEncodeBuffer exchangeCallback,
                        void *exchangeHandle)
    UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT;

/* Decodes a scalar value described by type from binary encoding. Decoding is
 * reentrant and can be safely called from signal handlers or interrupts.
 *
 * @param src The buffer with the binary encoded value. Must not be NULL.
 * @param offset The current position in the buffer. Must not be NULL. The value
 *        is advanced as decoding progresses.
 * @param dst The target value. Must not be NULL. The target is assumed to have
 *        size type->memSize. The value is reset to zero before decoding. If
 *        decoding fails, members are deleted and the value is reset (zeroed)
 *        again.
 * @param type The value type. Must not be NULL.
 * @param customTypesSize The number of non-standard datatypes contained in the
 *        customTypes array.
 * @param customTypes An array of non-standard datatypes (not included in
 *        UA_TYPES). Can be NULL if customTypesSize is zero.
 * @return Returns a statuscode whether decoding succeeded. */
UA_StatusCode
UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset,
                        void *dst, const UA_DataType *type,
                        UA_DecodeBinaryOptions *options)
    UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT;

const UA_DataType *
UA_findDataTypeByBinary(const UA_NodeId *typeId);

_UA_END_DECLS


/**** amalgamated original file "1_build/src_generated/open62541/transport_generated.h" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/




_UA_BEGIN_DECLS

/**
 * Every type is assigned an index in an array containing the type descriptions.
 * These descriptions are used during type handling (copying, deletion,
 * binary encoding, ...). */
#define UA_TRANSPORT_COUNT 9
extern UA_EXPORT UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT];

/* MessageType: Message Type and whether the message contains an intermediate chunk */
typedef enum {
    UA_MESSAGETYPE_ACK = 0x4B4341,
    UA_MESSAGETYPE_HEL = 0x4C4548,
    UA_MESSAGETYPE_MSG = 0x47534D,
    UA_MESSAGETYPE_OPN = 0x4E504F,
    UA_MESSAGETYPE_CLO = 0x4F4C43,
    UA_MESSAGETYPE_ERR = 0x525245,
    UA_MESSAGETYPE_RHE = 0x454852,
    UA_MESSAGETYPE_INVALID = 0x0,
    __UA_MESSAGETYPE_FORCE32BIT = 0x7fffffff
} UA_MessageType;

UA_STATIC_ASSERT(sizeof(UA_MessageType) == sizeof(UA_Int32), enum_must_be_32bit);

#define UA_TRANSPORT_MESSAGETYPE 0

UA_INLINABLE( void
UA_MessageType_init(UA_MessageType *p), {
    memset(p, 0, sizeof(UA_MessageType));
})

UA_INLINABLE( UA_MessageType *
UA_MessageType_new(void), {
    return (UA_MessageType*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_INLINABLE( UA_StatusCode
UA_MessageType_copy(const UA_MessageType *src, UA_MessageType *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_INLINABLE( void
UA_MessageType_clear(UA_MessageType *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_INLINABLE( void
UA_MessageType_delete(UA_MessageType *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_INLINABLE( UA_Boolean
UA_MessageType_equal(const UA_MessageType *p1, const UA_MessageType *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]) == UA_ORDER_EQ);
})


/* ChunkType: Type of the chunk */
typedef enum {
    UA_CHUNKTYPE_FINAL = 0x46000000,
    UA_CHUNKTYPE_INTERMEDIATE = 0x43000000,
    UA_CHUNKTYPE_ABORT = 0x41000000,
    __UA_CHUNKTYPE_FORCE32BIT = 0x7fffffff
} UA_ChunkType;

UA_STATIC_ASSERT(sizeof(UA_ChunkType) == sizeof(UA_Int32), enum_must_be_32bit);

#define UA_TRANSPORT_CHUNKTYPE 1

UA_INLINABLE( void
UA_ChunkType_init(UA_ChunkType *p), {
    memset(p, 0, sizeof(UA_ChunkType));
})

UA_INLINABLE( UA_ChunkType *
UA_ChunkType_new(void), {
    return (UA_ChunkType*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_INLINABLE( UA_StatusCode
UA_ChunkType_copy(const UA_ChunkType *src, UA_ChunkType *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_INLINABLE( void
UA_ChunkType_clear(UA_ChunkType *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_INLINABLE( void
UA_ChunkType_delete(UA_ChunkType *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_INLINABLE( UA_Boolean
UA_ChunkType_equal(const UA_ChunkType *p1, const UA_ChunkType *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]) == UA_ORDER_EQ);
})


/* TcpMessageHeader: TCP Header */
typedef struct {
    UA_UInt32 messageTypeAndChunkType;
    UA_UInt32 messageSize;
} UA_TcpMessageHeader;

#define UA_TRANSPORT_TCPMESSAGEHEADER 2

UA_INLINABLE( void
UA_TcpMessageHeader_init(UA_TcpMessageHeader *p), {
    memset(p, 0, sizeof(UA_TcpMessageHeader));
})

UA_INLINABLE( UA_TcpMessageHeader *
UA_TcpMessageHeader_new(void), {
    return (UA_TcpMessageHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpMessageHeader_copy(const UA_TcpMessageHeader *src, UA_TcpMessageHeader *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_INLINABLE( void
UA_TcpMessageHeader_clear(UA_TcpMessageHeader *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_INLINABLE( void
UA_TcpMessageHeader_delete(UA_TcpMessageHeader *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_INLINABLE( UA_Boolean
UA_TcpMessageHeader_equal(const UA_TcpMessageHeader *p1, const UA_TcpMessageHeader *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]) == UA_ORDER_EQ);
})


/* TcpHelloMessage: Hello Message */
typedef struct {
    UA_UInt32 protocolVersion;
    UA_UInt32 receiveBufferSize;
    UA_UInt32 sendBufferSize;
    UA_UInt32 maxMessageSize;
    UA_UInt32 maxChunkCount;
    UA_String endpointUrl;
} UA_TcpHelloMessage;

#define UA_TRANSPORT_TCPHELLOMESSAGE 3

UA_INLINABLE( void
UA_TcpHelloMessage_init(UA_TcpHelloMessage *p), {
    memset(p, 0, sizeof(UA_TcpHelloMessage));
})

UA_INLINABLE( UA_TcpHelloMessage *
UA_TcpHelloMessage_new(void), {
    return (UA_TcpHelloMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpHelloMessage_copy(const UA_TcpHelloMessage *src, UA_TcpHelloMessage *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpHelloMessage_clear(UA_TcpHelloMessage *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpHelloMessage_delete(UA_TcpHelloMessage *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_INLINABLE( UA_Boolean
UA_TcpHelloMessage_equal(const UA_TcpHelloMessage *p1, const UA_TcpHelloMessage *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]) == UA_ORDER_EQ);
})


/* TcpReverseHelloMessage */
typedef struct {
    UA_String serverUri;
    UA_String endpointUrl;
} UA_TcpReverseHelloMessage;

#define UA_TRANSPORT_TCPREVERSEHELLOMESSAGE 4

UA_INLINABLE( void
UA_TcpReverseHelloMessage_init(UA_TcpReverseHelloMessage *p), {
    memset(p, 0, sizeof(UA_TcpReverseHelloMessage));
})

UA_INLINABLE( UA_TcpReverseHelloMessage *
UA_TcpReverseHelloMessage_new(void), {
    return (UA_TcpReverseHelloMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpReverseHelloMessage_copy(const UA_TcpReverseHelloMessage *src, UA_TcpReverseHelloMessage *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpReverseHelloMessage_clear(UA_TcpReverseHelloMessage *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpReverseHelloMessage_delete(UA_TcpReverseHelloMessage *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_INLINABLE( UA_Boolean
UA_TcpReverseHelloMessage_equal(const UA_TcpReverseHelloMessage *p1, const UA_TcpReverseHelloMessage *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]) == UA_ORDER_EQ);
})


/* TcpAcknowledgeMessage: Acknowledge Message */
typedef struct {
    UA_UInt32 protocolVersion;
    UA_UInt32 receiveBufferSize;
    UA_UInt32 sendBufferSize;
    UA_UInt32 maxMessageSize;
    UA_UInt32 maxChunkCount;
} UA_TcpAcknowledgeMessage;

#define UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE 5

UA_INLINABLE( void
UA_TcpAcknowledgeMessage_init(UA_TcpAcknowledgeMessage *p), {
    memset(p, 0, sizeof(UA_TcpAcknowledgeMessage));
})

UA_INLINABLE( UA_TcpAcknowledgeMessage *
UA_TcpAcknowledgeMessage_new(void), {
    return (UA_TcpAcknowledgeMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpAcknowledgeMessage_copy(const UA_TcpAcknowledgeMessage *src, UA_TcpAcknowledgeMessage *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_INLINABLE( void
UA_TcpAcknowledgeMessage_clear(UA_TcpAcknowledgeMessage *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_INLINABLE( void
UA_TcpAcknowledgeMessage_delete(UA_TcpAcknowledgeMessage *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_INLINABLE( UA_Boolean
UA_TcpAcknowledgeMessage_equal(const UA_TcpAcknowledgeMessage *p1, const UA_TcpAcknowledgeMessage *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]) == UA_ORDER_EQ);
})


/* TcpErrorMessage: Error Message */
typedef struct {
    UA_UInt32 error;
    UA_String reason;
} UA_TcpErrorMessage;

#define UA_TRANSPORT_TCPERRORMESSAGE 6

UA_INLINABLE( void
UA_TcpErrorMessage_init(UA_TcpErrorMessage *p), {
    memset(p, 0, sizeof(UA_TcpErrorMessage));
})

UA_INLINABLE( UA_TcpErrorMessage *
UA_TcpErrorMessage_new(void), {
    return (UA_TcpErrorMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpErrorMessage_copy(const UA_TcpErrorMessage *src, UA_TcpErrorMessage *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_INLINABLE( void
UA_TcpErrorMessage_clear(UA_TcpErrorMessage *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_INLINABLE( void
UA_TcpErrorMessage_delete(UA_TcpErrorMessage *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_INLINABLE( UA_Boolean
UA_TcpErrorMessage_equal(const UA_TcpErrorMessage *p1, const UA_TcpErrorMessage *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]) == UA_ORDER_EQ);
})


/* AsymmetricAlgorithmSecurityHeader: Asymmetric Security Header */
typedef struct {
    UA_String securityPolicyUri;
    UA_ByteString senderCertificate;
    UA_ByteString receiverCertificateThumbprint;
} UA_AsymmetricAlgorithmSecurityHeader;

#define UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER 7

UA_INLINABLE( void
UA_AsymmetricAlgorithmSecurityHeader_init(UA_AsymmetricAlgorithmSecurityHeader *p), {
    memset(p, 0, sizeof(UA_AsymmetricAlgorithmSecurityHeader));
})

UA_INLINABLE( UA_AsymmetricAlgorithmSecurityHeader *
UA_AsymmetricAlgorithmSecurityHeader_new(void), {
    return (UA_AsymmetricAlgorithmSecurityHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_INLINABLE( UA_StatusCode
UA_AsymmetricAlgorithmSecurityHeader_copy(const UA_AsymmetricAlgorithmSecurityHeader *src, UA_AsymmetricAlgorithmSecurityHeader *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_INLINABLE( void
UA_AsymmetricAlgorithmSecurityHeader_clear(UA_AsymmetricAlgorithmSecurityHeader *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_INLINABLE( void
UA_AsymmetricAlgorithmSecurityHeader_delete(UA_AsymmetricAlgorithmSecurityHeader *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_INLINABLE( UA_Boolean
UA_AsymmetricAlgorithmSecurityHeader_equal(const UA_AsymmetricAlgorithmSecurityHeader *p1, const UA_AsymmetricAlgorithmSecurityHeader *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]) == UA_ORDER_EQ);
})


/* SequenceHeader: Secure Layer Sequence Header */
typedef struct {
    UA_UInt32 sequenceNumber;
    UA_UInt32 requestId;
} UA_SequenceHeader;

#define UA_TRANSPORT_SEQUENCEHEADER 8

UA_INLINABLE( void
UA_SequenceHeader_init(UA_SequenceHeader *p), {
    memset(p, 0, sizeof(UA_SequenceHeader));
})

UA_INLINABLE( UA_SequenceHeader *
UA_SequenceHeader_new(void), {
    return (UA_SequenceHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_INLINABLE( UA_StatusCode
UA_SequenceHeader_copy(const UA_SequenceHeader *src, UA_SequenceHeader *dst), {
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_INLINABLE( void
UA_SequenceHeader_clear(UA_SequenceHeader *p), {
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_INLINABLE( void
UA_SequenceHeader_delete(UA_SequenceHeader *p), {
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_INLINABLE( UA_Boolean
UA_SequenceHeader_equal(const UA_SequenceHeader *p1, const UA_SequenceHeader *p2), {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]) == UA_ORDER_EQ);
})


_UA_END_DECLS



/**** amalgamated original file "/src/ua_securechannel.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 */


struct UA_SecureChannel;
typedef struct UA_SecureChannel UA_SecureChannel;



_UA_BEGIN_DECLS

/* True for the ECC SecurityPolicy family, including the AEAD variants
 * (ECC_nistP256_AesGcm/ChaChaPoly, ECC_curve25519/448). Use this instead of
 * spelling out the policyType enum pair at each call site. */
static UA_INLINE UA_Boolean
UA_SecurityPolicy_isEcc(const UA_SecurityPolicy *policy) {
    return policy != NULL &&
        (policy->policyType == UA_SECURITYPOLICYTYPE_ECC ||
         policy->policyType == UA_SECURITYPOLICYTYPE_ECC_AEAD);
}

/* True for AEAD SecurityPolicies (AES-GCM / ChaCha20-Poly1305). These derive a
 * combined encryption key + IV (no separate signing key) and authenticate via
 * the cipher tag; the SecureChannel and EccEncryptedSecret code use this to
 * switch on the AEAD message layout. */
static UA_INLINE UA_Boolean
UA_SecurityPolicy_isAead(const UA_SecurityPolicy *policy) {
    return policy != NULL && policy->policyType == UA_SECURITYPOLICYTYPE_ECC_AEAD;
}

/* Forward-Declaration so the SecureChannel can point to a singly-linked list of
 * Sessions. This is only used in the server, not in the client. */
struct UA_Session;
typedef struct UA_Session UA_Session;

/* The message header of the OPC UA binary protocol is structured as follows:
 *
 * - MessageType (3 Byte)
 * - IsFinal (1 Byte)
 * - MessageSize (4 Byte)
 * *** UA_SECURECHANNEL_MESSAGEHEADER_LENGTH ***
 * - SecureChannelId (4 Byte)
 * *** UA_SECURECHANNEL_CHANNELHEADER_LENGTH ***
 * - SecurityHeader (4 Byte TokenId for symmetric, otherwise dynamic length)
 * - SequenceHeader (8 Byte)
 *   - SequenceNumber
 *   - RequestId
 */

#define UA_SECURECHANNEL_MESSAGEHEADER_LENGTH 8
#define UA_SECURECHANNEL_CHANNELHEADER_LENGTH 12
#define UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH 4
#define UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH 8
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH \
    (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +                \
     UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH)
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH   \
    (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +            \
    UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH +  \
     UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH)

/* Minimum length of a valid message (ERR message with an empty reason) */
#define UA_SECURECHANNEL_MESSAGE_MIN_LENGTH 16

/* For chunked requests */
typedef struct UA_Chunk {
    TAILQ_ENTRY(UA_Chunk) pointers;
    UA_ByteString bytes;
    UA_MessageType messageType;
    UA_ChunkType chunkType;
    UA_UInt32 requestId;
    UA_Boolean copied; /* Do the bytes point to a buffer from the network or was
                        * memory allocated for the chunk separately */
} UA_Chunk;

typedef TAILQ_HEAD(UA_ChunkQueue, UA_Chunk) UA_ChunkQueue;

typedef enum {
    UA_SECURECHANNELRENEWSTATE_NORMAL,

    /* Client has sent an OPN, but not received a response so far. */
    UA_SECURECHANNELRENEWSTATE_SENT,

    /* The server waits for the first request with the new token for the rollover.
     * The new token is stored in the altSecurityToken. The configured local and
     * remote symmetric encryption keys are the old ones. */
    UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER,

    /* The client already uses the new token. But he waits for the server to respond
     * with the new token to complete the rollover. The old token is stored in
     * altSecurityToken. The local symmetric encryption key is new. The remote
     * encryption key is the old one. */
    UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT
} UA_SecureChannelRenewState;

struct UA_SecureChannel {
    UA_SecureChannelState state;
    UA_SecureChannelRenewState renewState;
    UA_MessageSecurityMode securityMode;
    UA_ShutdownReason shutdownReason;

    UA_ConnectionConfig config;
    UA_String endpointUrl;
    UA_String remoteAddress;

    /* Connection handling in the EventLoop */
    UA_ConnectionManager *connectionManager;
    uintptr_t connectionId;

    /* The namespace mapping translates namespace indices of NodeIds during
     * de/encoding (client only) */
    UA_NamespaceMapping *namespaceMapping;

    /* Linked lists (only used in the server) */
    TAILQ_ENTRY(UA_SecureChannel) serverEntry;
    TAILQ_ENTRY(UA_SecureChannel) componentEntry;

    /* Rules for revolving the token with a renew OPN request: The client is
     * allowed to accept messages with the old token until the OPN response has
     * arrived. The server accepts the old token until one message secured with
     * the new token has arrived.
     *
     * We recognize whether nextSecurityToken contains a valid next token if the
     * ChannelId is not 0. */
    UA_ChannelSecurityToken securityToken;    /* Also contains the channelId */
    UA_ChannelSecurityToken altSecurityToken; /* Alternative token for the rollover.
                                               * See the renewState. */

    /* The endpoint and context of the channel */
    UA_SecurityPolicy *securityPolicy;
    void *channelContext; /* For interaction with the security policy */

    /* Properties derived from the SecurityPolicy URI, cached when the policy is
     * set (it is fixed for the channel's lifetime). This avoids re-evaluating
     * UA_SecurityPolicy_isEnhancedSecurity / _useLegacySequenceNumbers (which
     * scan the policy URI) on the per-chunk send and receive paths. */
    UA_Boolean enhancedSecurity;      /* UA_SecurityPolicy_isEnhancedSecurity */
    UA_Boolean legacySequenceNumbers; /* UA_SecurityPolicy_useLegacySequenceNumbers */

    /* OPC UA Part 6 v1.05.07 §6.7.5 "ChannelThumbprint" for
     * SecurityPolicies with secureChannelEnhancements = true.
     * The first OPN request signature is appended to the data signed by
     * the OPN response (and vice versa). Set on send, consumed on
     * receive, then cleared. Never used on OPN renewals. */
    UA_ByteString firstRequestSignature;

    /* OPC UA Part 6 v1.05.07 §6.8.1 step 2 "Extract" IKM chaining
     * accumulator for SecurityPolicies with secureChannelEnhancements =
     * true. The IKM is the size of the policy's shared secret (e.g. 32
     * bytes for P-256). On each renewal, the policy's generateKey
     * wrapper XORs the new shared secret with this value and writes the
     * result back. The SecureChannel passes this value as a prefix of
     * the `secret` ByteString to the policy's generateKey, where the
     * policy strips and updates it. Zero-length on the first OPN. */
    UA_ByteString currentIKM;

    /* OPC UA Part 6 v1.05.07 ChannelThumbprint: the (verified) signature
     * of the first OpenSecureChannel *response*. Captured once on the
     * first OPN (client: on response verify; server: on response sign)
     * and preserved across renewals. Used to bind the CreateSession /
     * ActivateSession SignatureData to this SecureChannel. Only set for
     * SecurityPolicies with secureChannelEnhancements = true. */
    UA_ByteString channelThumbprint;

    /* Asymmetric encryption info */
    UA_ByteString remoteCertificate;
    UA_Byte remoteCertificateThumbprint[20]; /* The thumbprint of the remote certificate */

    /* Symmetric encryption nonces. These are used to generate the key material
     * and must not be reused once the keys are in place.
     *
     * Nonces are also used during the CreateSession / ActivateSession
     * handshake. These are not handled here, as the Session handling can
     * overlap with a RenewSecureChannel. */
    UA_ByteString remoteNonce;
    UA_ByteString localNonce;

    UA_UInt32 receiveSequenceNumber;
    UA_UInt32 sendSequenceNumber;

    /* Sessions that are bound to the SecureChannel (singly-linked list, only
     * used in the server) */
    UA_Session *sessions;

    /* (Decrypted) chunks waiting to be processed */
    UA_ChunkQueue chunks;
    size_t chunksCount;
    size_t chunksLength;

    /* Received buffer from which no chunks have been extracted so far */
    UA_ByteString unprocessed;
    size_t unprocessedOffset;
    UA_Boolean unprocessedCopied;
    UA_DelayedCallback unprocessedDelayed;

    void *processOPNHeaderApplication;
    UA_StatusCode (*processOPNHeader)(void *application, UA_SecureChannel *channel,
                                      const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
};

void UA_SecureChannel_init(UA_SecureChannel *channel);

/* Trigger the shutdown */
void UA_SecureChannel_shutdown(UA_SecureChannel *channel,
                               UA_ShutdownReason shutdownReason);

/* Eventual cleanup after the channel has closed. It is possible to call _init
 * on the channel afterwards to reset it to the fresh status. */
void UA_SecureChannel_clear(UA_SecureChannel *channel);

/* Process the remote configuration in the HEL/ACK handshake. The connection
 * config is initialized with the local settings. */
UA_StatusCode
UA_SecureChannel_processHELACK(UA_SecureChannel *channel,
                               const UA_TcpAcknowledgeMessage *remoteConfig);

UA_StatusCode
UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel,
                                   UA_SecurityPolicy *securityPolicy,
                                   const UA_ByteString *remoteCertificate);

UA_StatusCode
UA_SecureChannel_setSecurityMode(UA_SecureChannel *channel,
                                 UA_MessageSecurityMode securityMode);

UA_Boolean
UA_SecureChannel_isConnected(UA_SecureChannel *channel);

/* Returns true if the channel has timed out. Performs the SecurityToken
 * rollover if required and possible. */
UA_Boolean
UA_SecureChannel_checkTimeout(UA_SecureChannel *channel,
                              UA_DateTime nowMonotonic);

/* Remove (partially) received unprocessed chunks */
void
UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel);

/* Wrapper function for generating a local nonce for the supplied channel. Uses
 * the random generator of the channels security policy to allocate and generate
 * a nonce with the specified length. */
UA_StatusCode
UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel);

UA_StatusCode
UA_SecureChannel_generateLocalKeys(UA_SecureChannel *channel);

UA_StatusCode
generateRemoteKeys(UA_SecureChannel *channel);

/* OPC UA Part 6 v1.05.07 (secureChannelEnhancements): build the
 * channel-bound CreateSession ServerSignature data
 *   channelThumbprint | clientNonce | H(serverChannelCert) |
 *   H(clientChannelCert) | serverNonce
 * Both the server (sign) and client (verify) call this with the same
 * logical values. `out` is allocated by the callee. */
UA_StatusCode
UA_SecureChannel_buildCreateSessionSignatureData(
    const UA_SecureChannel *channel, const UA_ByteString *clientNonce,
    const UA_ByteString *serverNonce, const UA_ByteString *serverChannelCert,
    const UA_ByteString *clientChannelCert, UA_ByteString *out);

/* OPC UA Part 6 v1.05.07: build the channel-bound ActivateSession
 * ClientSignature data
 *   channelThumbprint | serverNonce | H(serverAppCert) |
 *   H(serverChannelCert) | H(clientChannelCert) | clientNonce
 * `out` is allocated by the callee. */
UA_StatusCode
UA_SecureChannel_buildActivateSessionSignatureData(
    const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
    const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
    const UA_ByteString *serverChannelCert, const UA_ByteString *clientChannelCert,
    UA_ByteString *out);

/* OPC UA Part 6 v1.05.07: build the channel-bound ActivateSession
 * user-token (X.509) signature data
 *   channelThumbprint | serverNonce | H(serverAppCert) | H(serverChannelCert) |
 *   H(clientAppCert) | H(clientChannelCert) | clientNonce
 * This is the ClientSignature layout with an extra H(clientAppCert) - the
 * CLIENT's APPLICATION instance certificate - inserted before
 * H(clientChannelCert). NOTE: the user/X509-token certificate does NOT appear
 * in the signed data (it is conveyed and validated separately); the signature
 * only proves possession of the user key over the channel-bound data. */
UA_StatusCode
UA_SecureChannel_buildUserTokenSignatureData(
    const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
    const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
    const UA_ByteString *serverChannelCert, const UA_ByteString *clientAppCert,
    const UA_ByteString *clientChannelCert, UA_ByteString *out);

/**
 * Sending Messages
 * ---------------- */

/* When a fatal error occurs the Server shall send an Error Message to the
 * Client and close the socket. When a Client encounters one of these errors, it
 * shall also close the socket but does not send an Error Message. After the
 * socket is closed a Client shall try to reconnect automatically using the
 * mechanisms described in [...]. */
void
UA_SecureChannel_sendERR(UA_SecureChannel *channel, UA_TcpErrorMessage *error);

UA_StatusCode
UA_SecureChannel_sendOPN(UA_SecureChannel *channel, UA_UInt32 requestId,
                         const void *content, const UA_DataType *contentType);

UA_StatusCode
UA_SecureChannel_sendMSG(UA_SecureChannel *channel, UA_UInt32 requestId,
                         void *payload, const UA_DataType *payloadType);

UA_StatusCode
UA_SecureChannel_sendCLO(UA_SecureChannel *channel, UA_UInt32 requestId,
                         UA_CloseSecureChannelRequest *req);

/* The MessageContext is forwarded into the encoding layer so that we can send
 * chunks before continuing to encode. This lets us reuse a fixed chunk-sized
 * messages buffer. */
typedef struct {
    UA_SecureChannel *channel;
    UA_UInt32 requestId;
    UA_UInt32 messageType;

    UA_UInt16 chunksSoFar;
    size_t messageSizeSoFar;

    UA_ByteString messageBuffer;
    UA_Byte *buf_pos;
    const UA_Byte *buf_end;

    UA_Boolean final;
} UA_MessageContext;

/* Start the context of a new symmetric message. */
UA_StatusCode
UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
                        UA_UInt32 requestId, UA_MessageType messageType);

/* Encode the content and send out full chunks. If the return code is good, then
 * the ChunkInfo contains encoded content that has not been sent. If the return
 * code is bad, then the ChunkInfo has been cleaned up internally. */
UA_StatusCode
UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
                         const UA_DataType *contentType);

/* Sends a symmetric message already encoded in the context. The context is
 * cleaned up, also in case of errors. */
UA_StatusCode
UA_MessageContext_finish(UA_MessageContext *mc);

/* To be used when a failure occures when a MessageContext is open. Note that
 * the _encode and _finish methods will clean up internally. _abort can be run
 * on a MessageContext that has already been cleaned up before. */
void
UA_MessageContext_abort(UA_MessageContext *mc);

/**
 * Receive Message
 * --------------- */

/* Process a received buffer. This always has these three steps:
 *
 * 1. loadBuffer: The chunks in the SecureChannel are cut into chunks.
 *    The chunks can still point to the buffer.
 * 2. getCompleteMessage: Assemble chunks into a complete message. This is
 *    repeated until an error occours or an empty message is returned.
 * 3. persistBuffer: Make a copy of the remaining unpprocessed bytestring. So
 *    that the NetworkManager can reuse or free the packet memory.
 *
 * Note that only MSG and CLO messages are decrypted. HEL/ACK/OPN/... are
 * forwarded verbatim to the application. */
UA_StatusCode
UA_SecureChannel_loadBuffer(UA_SecureChannel *channel, const UA_ByteString buffer);

UA_StatusCode
UA_SecureChannel_getCompleteMessage(UA_SecureChannel *channel,
                                    UA_MessageType *messageType, UA_UInt32 *requestId,
                                    UA_ByteString *payload, UA_Boolean *copied,
                                    UA_DateTime nowMonotonic);

UA_StatusCode
UA_SecureChannel_persistBuffer(UA_SecureChannel *channel);

/* Internal methods in ua_securechannel_crypto.h */

void
hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start,
              const UA_Byte **buf_end);

/* Decrypt and verify via the signature. The chunk buffer is reused to hold the
 * decrypted data after the MessageHeader and SecurityHeader. The chunk length
 * is reduced by the signature, padding and encryption overhead.
 *
 * The offset argument points to the start of the encrypted content (beginning
 * with the SequenceHeader).*/
UA_StatusCode
decryptAndVerifyChunk(UA_SecureChannel *channel,
                      const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm,
                      const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
                      UA_MessageType messageType, UA_ByteString *chunk, size_t offset);

size_t
calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel);

UA_StatusCode
prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos,
                   const UA_Byte *buf_end, size_t totalLength,
                   size_t securityHeaderLength, UA_UInt32 requestId,
                   size_t *const finalLength);

/* Advance and return the next SequenceNumber to put into an outgoing chunk
 * (asymmetric OPN and symmetric MSG/CLO alike). Part 6 §6.7.2.4: the legacy
 * policies start at 1 and roll over to 1; the v1.05.07 enhanced/ECC policies
 * (LegacySequenceNumbers = false) start at 0 and roll over to 0. */
UA_UInt32
UA_SecureChannel_nextSequenceNumber(UA_SecureChannel *channel);

void
setBufPos(UA_MessageContext *mc);

UA_StatusCode
checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId,
               UA_DateTime nowMonotonic);

UA_StatusCode
checkAsymHeader(UA_SecureChannel *channel,
                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);

void
padChunk(UA_SecureChannel *channel,
         const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm,
         const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
         const UA_Byte *start, UA_Byte **pos);

UA_StatusCode
signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength,
                   UA_ByteString *buf, size_t securityHeaderLength,
                   size_t totalLength);

UA_StatusCode
signAndEncryptSym(UA_MessageContext *messageContext,
                  size_t preSigLength, size_t totalLength);

/**
 * Log Helper
 * ----------
 * C99 requires at least one element for the variadic argument. If the log
 * statement has no variable arguments, supply an additional NULL. It will be
 * ignored by printf.
 *
 * We have to jump through some hoops to enable the use of format strings
 * without arguments since (pedantic) C99 does not allow variadic macros with
 * zero arguments. So we add a dummy argument that is not printed (%.0s is
 * string of length zero). */

#define UA_LOG_CHANNEL_INTERNAL(LOGGER, LEVEL, CHANNEL, MSG, ...)       \
    do {                                                                \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SECURECHANNEL,            \
                       "TCP %lu\t| SC %" PRIu32 "\t| " MSG "%.0s", \
                       (long unsigned)(CHANNEL)->connectionId,          \
                       (CHANNEL)->securityToken.channelId, __VA_ARGS__); \
    } \
    } while (0)

#define UA_LOG_TRACE_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, TRACE, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, DEBUG, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_INFO_CHANNEL(LOGGER, CHANNEL, ...)                       \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, INFO, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_WARNING_CHANNEL(LOGGER, CHANNEL, ...)                    \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, WARNING, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_ERROR_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, ERROR, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_FATAL_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, FATAL, CHANNEL, __VA_ARGS__, ""))

_UA_END_DECLS


/**** amalgamated original file "/src/util/ua_util_internal.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 *    Copyright 2025 (c) Siemens AG (Author: Tin Raic)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#define UA_INTERNAL



_UA_BEGIN_DECLS

/* Macro-Expand for MSVC workarounds */
#define UA_MACRO_EXPAND(x) x

/* Often-used macro to get the beginning of the parent data structure */
#ifndef container_of
# define container_of(ptr, type, member) \
    (type *)((uintptr_t)ptr - offsetof(type,member))
#endif

/* Try if the type of the value can be adjusted "in situ" to the target type.
 * That can be done, for example, to map between int32 and an enum.
 *
 * This can also "unwrap" a type. For example: string -> array of bytes
 *
 * If value->data is changed during adjustType, free the pointer afterwards (if
 * you did not keep the original variant for _clear). */
void
adjustType(UA_Variant *value, const UA_DataType *targetType);

/* Short names for integer. These are not exposed on the public API, since many
 * user-applications make the same definitions in their headers. */
typedef UA_Byte u8;
typedef UA_SByte i8;
typedef UA_UInt16 u16;
typedef UA_Int16 i16;
typedef UA_UInt32 u32;
typedef UA_Int32 i32;
typedef UA_UInt64 u64;
typedef UA_Int64 i64;
typedef UA_StatusCode status;

/* Well-known ReferenceTypes */
UA_StatusCode
lookupRefType(UA_Server *server, UA_QualifiedName *qn, UA_NodeId *outRefTypeId);

/* Returns the canonical BrowseName of the ReferenceType or the encoded
 * NodeId. The outBN is assumed to be pre-allocated with a buffer. This fails if
 * the NodeId contains an '>' character, which makes the parsing ambigous. */
UA_StatusCode
getRefTypeBrowseName(const UA_NodeId *refTypeId, UA_String *outBN);

typedef enum {
    UA_ESCAPING_NONE = 0,
    UA_ESCAPING_AND,
    UA_ESCAPING_AND_EXTENDED,
    UA_ESCAPING_PERCENT,
    UA_ESCAPING_PERCENT_EXTENDED
} UA_Escaping;

static UA_INLINE UA_Boolean
isReservedAnd(u8 c) {
    return (c == '/' || c == '.' || c == '<' || c == '>' ||
            c == ':' || c == '#' || c == '!' || c == '&');
}

static UA_INLINE UA_Boolean
isReservedAndExtended(u8 c) {
    return (isReservedAnd(c) || c == ',' || c == '(' || c == ')' ||
            c == '[' || c == ']' || c <= ' ' || c == 127);
}

static UA_INLINE UA_Boolean
isReservedPercent(u8 c) {
    return (c == ';'  || c == '%' || c <= ' ' || c == 127);
}

static UA_INLINE UA_Boolean
isReservedPercentExtended(u8 c) {
    return (isReservedPercent(c) || c == ':' || c == '#' || c == '[' || c == ']' ||
            c == '&' || c == '(' || c == ')' || c == ',' || c == '<' || c == '>' ||
            c == '`' || c == '/' || c == '\\' || c == '"' || c == '\'' );
}

/* Unescape string. The copyEscape boolean indicates whether a copy of the
 * string should be made if an escaped character is found. Otherwise the string
 * is unescaped in-place. */
UA_StatusCode
UA_String_unescape(UA_String *str, UA_Boolean copyEscape, UA_Escaping esc);

/* Size of the string with the escaping */
size_t
UA_String_escapedSize(const UA_String s, UA_Escaping esc);

/* Insert string with escaping at the defined position.
 * Returns the length of the inserted escaped string.
 * This is an unsafe procedure if not enough space is available. */
size_t
UA_String_escapeInsert(u8 *pos, const UA_String s2, UA_Escaping esc);

/* Escape s2 and append it to s. Memory is allocated internally. */
UA_StatusCode
UA_String_escapeAppend(UA_String *s, const UA_String s2, UA_Escaping esc);

/* Case insensitive lookup. Returns UA_ATTRIBUTEID_INVALID if not found. */
UA_AttributeId
UA_AttributeId_fromName(const UA_String name);

/* Special version of NodeId_print where the identifier component is escaped as
 * well (not just the NamespaceUri). For percent-escaping (URL format), the
 * ByteString body is in base64url format (no +/, no =-padding). */
UA_StatusCode
nodeId_printEscape(const UA_NodeId *id, UA_String *output,
                   const UA_NamespaceMapping *nsMapping, UA_Escaping idEsc);

#ifdef UA_TYPES_SIMPLEATTRIBUTEOPERAND
UA_StatusCode
sao_parseWithDefaultNsIdx(UA_SimpleAttributeOperand *sao,
                          const UA_String str, UA_UInt16 defaultNsIndex);
#endif

UA_StatusCode
encodeDateTime(const UA_DateTime dt, UA_String *output);

/***************/
/* Log Helpers */
/***************/

extern char * securityModeNames[4];

/**
 * Error checking macros
 */

static UA_INLINE UA_Boolean
isGood(UA_StatusCode code) {
    return code == UA_STATUSCODE_GOOD;
}

static UA_INLINE UA_Boolean
isNonNull(const void *ptr) {
    return ptr != NULL;
}

static UA_INLINE UA_Boolean
isTrue(uint8_t expr) {
    return expr;
}

#define UA_CHECK(A, EVAL_ON_ERROR)                                                       \
    do {                                                                                 \
        if(UA_UNLIKELY(!isTrue(A))) {                                                    \
            EVAL_ON_ERROR;                                                               \
        }                                                                                \
    } while(0)

#define UA_CHECK_STATUS(STATUSCODE, EVAL_ON_ERROR)                                       \
    UA_CHECK(isGood(STATUSCODE), EVAL_ON_ERROR)

#define UA_CHECK_MEM(STATUSCODE, EVAL_ON_ERROR)                                       \
    UA_CHECK(isNonNull(STATUSCODE), EVAL_ON_ERROR)

#ifdef UA_DEBUG_FILE_LINE_INFO
#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...)           \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (%s:%d: StatusCode: %s)", __VA_ARGS__,   \
                        __FILE__, __LINE__, UA_StatusCode_name(STATUSCODE));             \
                 EVAL))
#else
#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...)           \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (StatusCode: %s)", __VA_ARGS__,   \
                        UA_StatusCode_name(STATUSCODE));             \
                 EVAL))
#endif

#define UA_CHECK_LOG(A, EVAL, LEVEL, LOGGER, CAT, ...)                                   \
    UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(A, UA_STATUSCODE_BAD, EVAL, UA_LOG_##LEVEL,    \
                                          LOGGER, CAT, __VA_ARGS__, ""))

#define UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, LEVEL, LOGGER, CAT, ...)                   \
    UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isGood(STATUSCODE), STATUSCODE,  \
                                          EVAL, UA_LOG_##LEVEL, LOGGER, CAT,             \
                                          __VA_ARGS__, ""))

#define UA_CHECK_MEM_LOG(PTR, EVAL, LEVEL, LOGGER, CAT, ...)                   \
    UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isNonNull(PTR), UA_STATUSCODE_BADOUTOFMEMORY,  \
                                          EVAL, UA_LOG_##LEVEL, LOGGER, CAT,             \
                                          __VA_ARGS__, ""))

/**
 * Check Macros
 * Usage examples:
 *
 *    void *data = malloc(...);
 *    UA_CHECK(data, return error);
 *
 *    UA_StatusCode rv = some_func(...);
 *    UA_CHECK_STATUS(rv, return rv);
 *
 *    UA_Logger *logger = &server->config.logger;
 *    rv = bar_func(...);
 *    UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SERVER, "msg & args %s", "arg");
 */
#define UA_CHECK_FATAL(A, EVAL, LOGGER, CAT, ...)                                        \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_ERROR(A, EVAL, LOGGER, CAT, ...)                                        \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_WARN(A, EVAL, LOGGER, CAT, ...)                                         \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_INFO(A, EVAL, LOGGER, CAT, ...)                                         \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, INFO, LOGGER, CAT, __VA_ARGS__))

#define UA_CHECK_STATUS_FATAL(STATUSCODE, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_ERROR(STATUSCODE, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_WARN(STATUSCODE, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_INFO(STATUSCODE, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, INFO, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_DEBUG(STATUSCODE, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, DEBUG, LOGGER, CAT, __VA_ARGS__))

#define UA_CHECK_MEM_FATAL(PTR, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_MEM_ERROR(PTR, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_MEM_WARN(PTR, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_MEM_INFO(PTR, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, INFO, LOGGER, CAT, __VA_ARGS__))

/**
 * Utility Functions
 * ----------------- */

#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
# ifdef UA_ARCHITECTURE_WIN32
#  include <io.h>
#  define UA_fileExists(X) ( _access(X, 0) == 0)
# else
#  include <unistd.h>
#  define UA_fileExists(X) ( access(X, 0) == 0)
# endif
#endif

void
UA_cleanupDataTypeWithCustom(UA_DataTypeArray *customTypes);

/* Get the number of optional fields contained in an structure type */
size_t UA_EXPORT
getCountOfOptionalFields(const UA_DataType *type);

/* Dump packet for debugging / fuzzing */
#ifdef UA_DEBUG_DUMP_PKGS
void UA_EXPORT
UA_dump_hex_pkg(UA_Byte* buffer, size_t bufferLen);
#endif

/* Get pointer to leaf certificate of a specified valid chain of DER encoded
 * certificates */
UA_ByteString getLeafCertificate(UA_ByteString chain);

/* Unions that represent any of the supported request or response message */
typedef union {
    UA_RequestHeader requestHeader;
    UA_FindServersRequest findServersRequest;
    UA_GetEndpointsRequest getEndpointsRequest;
#ifdef UA_ENABLE_DISCOVERY
# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_FindServersOnNetworkRequest findServersOnNetworkRequest;
# endif
    UA_RegisterServerRequest registerServerRequest;
    UA_RegisterServer2Request registerServer2Request;
#endif
    UA_OpenSecureChannelRequest openSecureChannelRequest;
    UA_CreateSessionRequest createSessionRequest;
    UA_ActivateSessionRequest activateSessionRequest;
    UA_CloseSessionRequest closeSessionRequest;
    UA_AddNodesRequest addNodesRequest;
    UA_AddReferencesRequest addReferencesRequest;
    UA_DeleteNodesRequest deleteNodesRequest;
    UA_DeleteReferencesRequest deleteReferencesRequest;
    UA_BrowseRequest browseRequest;
    UA_BrowseNextRequest browseNextRequest;
    UA_TranslateBrowsePathsToNodeIdsRequest translateBrowsePathsToNodeIdsRequest;
    UA_RegisterNodesRequest registerNodesRequest;
    UA_UnregisterNodesRequest unregisterNodesRequest;
    UA_ReadRequest readRequest;
    UA_WriteRequest writeRequest;
#ifdef UA_ENABLE_HISTORIZING
    UA_HistoryReadRequest historyReadRequest;
    UA_HistoryUpdateRequest historyUpdateRequest;
#endif
#ifdef UA_ENABLE_METHODCALLS
    UA_CallRequest callRequest;
#endif
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_CreateMonitoredItemsRequest createMonitoredItemsRequest;
    UA_DeleteMonitoredItemsRequest deleteMonitoredItemsRequest;
    UA_ModifyMonitoredItemsRequest modifyMonitoredItemsRequest;
    UA_SetMonitoringModeRequest setMonitoringModeRequest;
    UA_CreateSubscriptionRequest createSubscriptionRequest;
    UA_ModifySubscriptionRequest modifySubscriptionRequest;
    UA_SetPublishingModeRequest setPublishingModeRequest;
    UA_PublishRequest publishRequest;
    UA_RepublishRequest republishRequest;
    UA_DeleteSubscriptionsRequest deleteSubscriptionsRequest;
#endif
} UA_Request;

typedef union {
    UA_ResponseHeader responseHeader;
    UA_FindServersResponse findServersResponse;
    UA_GetEndpointsResponse getEndpointsResponse;
#ifdef UA_ENABLE_DISCOVERY
# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_FindServersOnNetworkResponse findServersOnNetworkResponse;
# endif
    UA_RegisterServerResponse registerServerResponse;
    UA_RegisterServer2Response registerServer2Response;
#endif
    UA_OpenSecureChannelResponse openSecureChannelResponse;
    UA_CreateSessionResponse createSessionResponse;
    UA_ActivateSessionResponse activateSessionResponse;
    UA_CloseSessionResponse closeSessionResponse;
    UA_AddNodesResponse addNodesResponse;
    UA_AddReferencesResponse addReferencesResponse;
    UA_DeleteNodesResponse deleteNodesResponse;
    UA_DeleteReferencesResponse deleteReferencesResponse;
    UA_BrowseResponse browseResponse;
    UA_BrowseNextResponse browseNextResponse;
    UA_TranslateBrowsePathsToNodeIdsResponse translateBrowsePathsToNodeIdsResponse;
    UA_RegisterNodesResponse registerNodesResponse;
    UA_UnregisterNodesResponse unregisterNodesResponse;
    UA_ReadResponse readResponse;
    UA_WriteResponse writeResponse;
#ifdef UA_ENABLE_HISTORIZING
    UA_HistoryReadResponse historyReadResponse;
    UA_HistoryUpdateResponse historyUpdateResponse;
#endif
#ifdef UA_ENABLE_METHODCALLS
    UA_CallResponse callResponse;
#endif
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_CreateMonitoredItemsResponse createMonitoredItemsResponse;
    UA_DeleteMonitoredItemsResponse deleteMonitoredItemsResponse;
    UA_ModifyMonitoredItemsResponse modifyMonitoredItemsResponse;
    UA_SetMonitoringModeResponse setMonitoringModeResponse;
    UA_CreateSubscriptionResponse createSubscriptionResponse;
    UA_ModifySubscriptionResponse modifySubscriptionResponse;
    UA_SetPublishingModeResponse setPublishingModeResponse;
    UA_PublishResponse publishResponse;
    UA_RepublishResponse republishResponse;
    UA_DeleteSubscriptionsResponse deleteSubscriptionsResponse;
#endif
} UA_Response;

/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles
 * ASCII strings, and not UTF8! */
UA_Boolean UA_EXPORT
UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2);

/********************/
/* Encoding Helpers */
/********************/

/* out must be a buffer with at least 36 elements, the length of every guid */
void UA_Guid_to_hex(const UA_Guid *guid, u8* out, UA_Boolean lower);

#define UA_ENCODING_HELPERS(TYPE, UPCASE_TYPE)                          \
    static UA_INLINE size_t                                             \
    UA_##TYPE##_calcSizeBinary(const UA_##TYPE *src) {                    \
        return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE], NULL); \
    }                                                                   \
    static UA_INLINE UA_StatusCode                                      \
    UA_##TYPE##_encodeBinary(const UA_##TYPE *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { \
        return UA_encodeBinaryInternal(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE], \
                                       bufPos, &bufEnd, NULL, NULL, NULL); \
    }                                                                   \
    static UA_INLINE UA_StatusCode                                      \
    UA_##TYPE##_decodeBinary(const UA_ByteString *src, size_t *offset, UA_##TYPE *dst) { \
    return UA_decodeBinaryInternal(src, offset, dst, \
                                   &UA_TYPES[UA_TYPES_##UPCASE_TYPE], NULL); \
    }

UA_ENCODING_HELPERS(Boolean, BOOLEAN)
UA_ENCODING_HELPERS(SByte, SBYTE)
UA_ENCODING_HELPERS(Byte, BYTE)
UA_ENCODING_HELPERS(Int16, INT16)
UA_ENCODING_HELPERS(UInt16, UINT16)
UA_ENCODING_HELPERS(Int32, INT32)
UA_ENCODING_HELPERS(UInt32, UINT32)
UA_ENCODING_HELPERS(Int64, INT64)
UA_ENCODING_HELPERS(UInt64, UINT64)
UA_ENCODING_HELPERS(Float, FLOAT)
UA_ENCODING_HELPERS(Double, DOUBLE)
UA_ENCODING_HELPERS(String, STRING)
UA_ENCODING_HELPERS(DateTime, DATETIME)
UA_ENCODING_HELPERS(Guid, GUID)
UA_ENCODING_HELPERS(ByteString, BYTESTRING)
UA_ENCODING_HELPERS(XmlElement, XMLELEMENT)
UA_ENCODING_HELPERS(NodeId, NODEID)
UA_ENCODING_HELPERS(ExpandedNodeId, EXPANDEDNODEID)
UA_ENCODING_HELPERS(StatusCode, STATUSCODE)
UA_ENCODING_HELPERS(QualifiedName, QUALIFIEDNAME)
UA_ENCODING_HELPERS(LocalizedText, LOCALIZEDTEXT)
UA_ENCODING_HELPERS(ExtensionObject, EXTENSIONOBJECT)
UA_ENCODING_HELPERS(DataValue, DATAVALUE)
UA_ENCODING_HELPERS(Variant, VARIANT)
UA_ENCODING_HELPERS(DiagnosticInfo, DIAGNOSTICINFO)

/****************************/
/* Legacy Secret Encryption */
/****************************/

UA_StatusCode
encryptSecretLegacy(const UA_SecurityPolicy *sp, void *spContext,
                    const UA_ByteString serverSessionNonce,
                    UA_ByteString *tokenData);

UA_StatusCode
decryptSecretLegacy(const UA_SecurityPolicy *sp, void *spContext,
                    const UA_ByteString serverSessionNonce,
                    UA_ByteString *tokenData);

/******************/
/* ECC Encryption */
/******************/

UA_StatusCode
encryptUserIdentityTokenEcc(UA_Logger *logger, UA_SecureChannel *channel,
                            const UA_SecurityPolicy *sp, void *spContext,
                            UA_ByteString *tokenData,
                            const UA_ByteString serverSessionNonce,
                            const UA_ByteString serverEphemeralPubKey);

/* If the EccEncryptedSecret does not define a certificate, check if the
 * SecureChannel uses the same SecurityPolicy and reuse its context. */
UA_StatusCode
decryptUserTokenEcc(UA_Logger *logger, UA_SecureChannel *channel,
                    const UA_SecurityPolicy *sp, void *spContext,
                    UA_ByteString sessionServerNonce,
                    UA_ByteString *es);

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_session.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */




_UA_BEGIN_DECLS

#define UA_MAXCONTINUATIONPOINTS 32

struct ContinuationPoint;
typedef struct ContinuationPoint ContinuationPoint;

/* Returns the next entry in the linked list */
ContinuationPoint *
ContinuationPoint_clear(ContinuationPoint *cp);

struct UA_Subscription;
typedef struct UA_Subscription UA_Subscription;

#ifdef UA_ENABLE_SUBSCRIPTIONS
typedef struct UA_PublishResponseEntry {
    SIMPLEQ_ENTRY(UA_PublishResponseEntry) listEntry;
    UA_UInt32 requestId;
    UA_DateTime maxTime; /* Based on the TimeoutHint of the request */
    UA_PublishResponse response;
} UA_PublishResponseEntry;
#endif

struct UA_Session {
    UA_Session *next; /* singly-linked list */
    UA_SecureChannel *channel; /* The pointer back to the SecureChannel in the session. */

    UA_NodeId sessionId;
    UA_NodeId authenticationToken;
    UA_String sessionName;
    UA_Boolean activated;

    /* For ECC, client and server exchange ephemeral keys used for the
     * EccEncryptedSecret. The ephemeral keys have to be attached to the session
     * (and not the SecureChannel) so that the session can be re-activated on a
     * different SecureChannel. The SecurityPolicy "context" is created with the
     * client's ApplicationInstanceCertificate. */
    UA_SecurityPolicy *sessionSp;
    void *sessionSpContext;

    void *context; /* Pointer assigned by the user in the
                    * accessControl->activateSession context */

    UA_ByteString serverNonce;

    /* The clientNonce from the CreateSession request. Retained for the
     * v1.05.07 channel-bound ActivateSession ClientSignature verification
     * (secureChannelEnhancements). */
    UA_ByteString clientNonce;

    UA_ApplicationDescription clientDescription;
    UA_ByteString clientCertificate; /* Must be the same as for the
                                      * SecureChannel. If the SecureChannel is
                                      * #None, verify and store here. */
    UA_String clientUserIdOfSession;
    UA_Double timeout; /* in ms */
    UA_DateTime validTill;

    UA_KeyValueMap attributes;

    /* TODO: Currently unused */
    UA_UInt32 maxRequestMessageSize;
    UA_UInt32 maxResponseMessageSize;

    UA_UInt16         availableContinuationPoints;
    ContinuationPoint *continuationPoints;

    /* Localization information */
    size_t localeIdsSize;
    UA_String *localeIds;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* The queue is ordered according to the priority byte (higher bytes come
     * first). When a late subscription finally publishes, then it is pushed to
     * the back within the sub-set of subscriptions that has the same priority
     * (round-robin scheduling). */
    size_t subscriptionsSize;
    TAILQ_HEAD(, UA_Subscription) subscriptions;

    size_t responseQueueSize;
    SIMPLEQ_HEAD(, UA_PublishResponseEntry) responseQueue;

    size_t totalRetransmissionQueueSize; /* Retransmissions of all subscriptions */
#endif

#ifdef UA_ENABLE_DIAGNOSTICS
    UA_SessionSecurityDiagnosticsDataType securityDiagnostics;
    UA_SessionDiagnosticsDataType diagnostics;
#endif
};

/**
 * Session Lifecycle
 * ----------------- */

void UA_Session_init(UA_Session *session);
void UA_Session_clear(UA_Session *session, UA_Server *server);
void UA_Session_attachToSecureChannel(UA_Server *server, UA_Session *session,
                                      UA_SecureChannel *channel);
void UA_Session_detachFromSecureChannel(UA_Server *server, UA_Session *session);
UA_StatusCode UA_Session_generateNonce(UA_Session *session);

/* If any activity on a session happens, the timeout is extended */
void UA_Session_updateLifetime(UA_Session *session, UA_DateTime now,
                               UA_DateTime nowMonotonic);

void
notifySession(UA_Server *server, UA_Session *session,
              UA_ApplicationNotificationType type);

/**
 * Subscription handling
 * --------------------- */

#ifdef UA_ENABLE_SUBSCRIPTIONS

void
UA_Session_attachSubscription(UA_Session *session, UA_Subscription *sub);

/* If releasePublishResponses is true and the last subscription is removed, all
 * outstanding PublishResponse are sent with a StatusCode. But we don't do that
 * if a Subscription is only detached for modification. */
void
UA_Session_detachSubscription(UA_Server *server, UA_Session *session,
                              UA_Subscription *sub, UA_Boolean releasePublishResponses);

UA_Subscription *
UA_Session_getSubscriptionById(UA_Session *session,
                               UA_UInt32 subscriptionId);


void
UA_Session_queuePublishReq(UA_Session *session,
                           UA_PublishResponseEntry* entry,
                           UA_Boolean head);

UA_PublishResponseEntry *
UA_Session_dequeuePublishReq(UA_Session *session);

#endif

/**
 * Log Helper
 * ----------
 * We have to jump through some hoops to enable the use of format strings
 * without arguments since (pedantic) C99 does not allow variadic macros with
 * zero arguments. So we add a dummy argument that is not printed (%.0s is
 * string of length zero). */

#define UA_LOG_SESSION_INTERNAL(LOGGER, LEVEL, SESSION, MSG, ...)       \
    do {                                                                \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_String sessionName = (SESSION) ? (SESSION)->sessionName: UA_STRING_NULL; \
        unsigned long sockId = ((SESSION) && (SESSION)->channel) ?      \
            (unsigned long)(SESSION)->channel->connectionId : 0;        \
        UA_UInt32 chanId = ((SESSION) && (SESSION)->channel) ?          \
            (SESSION)->channel->securityToken.channelId : 0;            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SESSION,                  \
                       "TCP %lu\t| SC %" PRIu32 "\t| Session \"%S\"\t| " MSG "%.0s", \
                       sockId, chanId, sessionName, __VA_ARGS__);       \
    }                                                                   \
    } while (0)

#define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, TRACE, SESSION, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, DEBUG, SESSION, __VA_ARGS__, ""))
#define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...)                       \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, INFO, SESSION, __VA_ARGS__, ""))
#define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...)                    \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, WARNING, SESSION, __VA_ARGS__, ""))
#define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, ERROR, SESSION, __VA_ARGS__, ""))
#define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, FATAL, SESSION, __VA_ARGS__, ""))

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_subscription.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018, 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */




_UA_BEGIN_DECLS

#ifdef UA_ENABLE_SUBSCRIPTIONS

/* MonitoredItems create Notifications. Subscriptions collect Notifications from
 * (several) MonitoredItems and publish them to the client.
 *
 * Notifications are put into two queues at the same time. One for the
 * MonitoredItem that generated the notification. Here we can remove it if the
 * space reserved for the MonitoredItem runs full. The second queue is the
 * "global" queue for all Notifications generated in a Subscription. For
 * publication, the notifications are taken out of the Subscription's queue in
 * the order of their creation. */

/*****************/
/* Notifications */
/*****************/

/* A notification was not (yet) added to the queue of a Subscription */
#define UA_SUBSCRIPTION_QUEUE_SENTINEL ((UA_Notification*)0x01)

typedef struct UA_Notification {
    /* The subEntry can be a sentinel value to indicate that the Notification is
     * not enqueue in the Subscription. This is the case when the Subscription
     * is non-reporting.
     *
     * The monEntry is always set - the Notification must always be enqueued to
     * the MonitoredItem right after its creation with UA_Notification_new. */
    TAILQ_ENTRY(UA_Notification) subEntry; /* Notification list of the Subscription */
    TAILQ_ENTRY(UA_Notification) monEntry; /* Notification list of the MonitoredItem */
    UA_MonitoredItem *mon; /* Always set */

    /* The event field is used if mon->attributeId is the EventNotifier */
    union {
        UA_MonitoredItemNotification dataChange;
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        UA_EventFieldList event;
#endif
    } data;

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    UA_Boolean isOverflowEvent; /* Counted manually */
#endif
} UA_Notification;

/* Initializes and sets the sentinel pointers. Only create a notification if it
 * is also going to be immediately enqueued to a MonitoredItem (see below). */
UA_Notification * UA_Notification_new(void);

/* Notifications are always added to the queue of a MonitoredItem. That queue
 * can overflow. If Notifications are reported, they are also added to the queue
 * of the Subscription. There they are picked up by the publishing callback.
 *
 * There are two ways Notifications can be put into the global queue of the
 * Subscription: They are added because the MonitoringMode of the MonitoredItem
 * is "reporting". Or the MonitoringMode is "sampling" and a link is trigered
 * that puts the last Notification into the global queue. */
void UA_Notification_enqueueAndTrigger(UA_Server *server,
                                       UA_Notification *n);

/* A NotificationMessage contains an array of notifications.
 * Sent NotificationMessages are stored for the republish service. */
typedef struct UA_NotificationMessageEntry {
    TAILQ_ENTRY(UA_NotificationMessageEntry) listEntry;
    UA_NotificationMessage message;
} UA_NotificationMessageEntry;

/* Queue Definitions */
typedef TAILQ_HEAD(NotificationQueue, UA_Notification) NotificationQueue;
typedef TAILQ_HEAD(NotificationMessageQueue, UA_NotificationMessageEntry)
    NotificationMessageQueue;

/*****************/
/* MonitoredItem */
/*****************/

/* Maximum number of outstanding async reads per MonitoredItem.
 * This protects against unbounded memory usage. */
#define UA_MONITOREDITEM_ASYNC_MAX 8

/* The type of sampling for MonitoredItems depends on the sampling interval.
 *
 * >0: Cyclic callback
 * =0: Attached to the node. Sampling is triggered after every "write".
 * <0: Attached to the subscription. Triggered just before every "publish". */
typedef enum {
    UA_MONITOREDITEMSAMPLINGTYPE_NONE = 0,
    UA_MONITOREDITEMSAMPLINGTYPE_CYCLIC, /* Cyclic callback */
    UA_MONITOREDITEMSAMPLINGTYPE_EVENT,  /* Attached to the node. Can be a "write
                                          * event" for DataChange MonitoredItems
                                          * with a zero sampling interval .*/
    UA_MONITOREDITEMSAMPLINGTYPE_PUBLISH /* Attached to the subscription */
} UA_MonitoredItemSamplingType;

struct UA_MonitoredItem {
    UA_DelayedCallback delayedFreePointers;
    LIST_ENTRY(UA_MonitoredItem) listEntry; /* Linked list in the Subscription */
    UA_Subscription *subscription;          /* Always non-NULL */
    UA_UInt32 monitoredItemId;

    /* Status and Settings */
    UA_ReadValueId itemToMonitor;
    UA_MonitoringMode monitoringMode;
    UA_TimestampsToReturn timestampsToReturn;
    UA_Boolean registered;       /* Registered in the server / Subscription */
    UA_DateTime triggeredUntil;  /* If the MonitoringMode is SAMPLING,
                                  * triggering the MonitoredItem puts the latest
                                  * Notification into the publishing queue (of
                                  * the Subscription). In addition, the first
                                  * new sample is also published (and not just
                                  * sampled) if it occurs within the duration of
                                  * one publishing cycle after the triggering. */

    /* If the filter is a UA_DataChangeFilter: The DataChangeFilter always
     * contains an absolute deadband definition. Part 8, §6.2 gives the
     * following formula to test for percentage deadbands:
     *
     * DataChange if (absolute value of (last cached value - current value)
     *                > (deadbandValue/100.0) * ((high–low) of EURange)))
     *
     * So we can convert from a percentage to an absolute deadband and keep
     * the hot code path simple.
     *
     * TODO: Store the percentage deadband to recompute when the UARange is
     * changed at runtime of the MonitoredItem */
    UA_MonitoringParameters parameters;

    /* Sampling */
    UA_MonitoredItemSamplingType samplingType;
    union {
        UA_UInt64 callbackId;
        UA_MonitoredItem *nodeListNext; /* Event-Based: Attached to Node */
        LIST_ENTRY(UA_MonitoredItem) subscriptionSampling; /* Linked to publish
                                                            * interval */
    } sampling;
    UA_DataValue lastValue;
    UA_UInt32 outstandingAsyncReads; /* at most UA_MONITOREDITEM_ASYNC_MAX */

    /* Triggering Links */
    size_t triggeringLinksSize;
    UA_UInt32 *triggeringLinks;

    /* Notification Queue */
    NotificationQueue queue;
    size_t queueSize; /* This is the current size. See also the configured
                       * (maximum) queueSize in the parameters. */
    size_t eventOverflows; /* Separate counter for the queue. Can at most double
                            * the queue size */
};

void UA_MonitoredItem_init(UA_MonitoredItem *mon);
void UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *mon);
void UA_MonitoredItem_removeOverflowInfoBits(UA_MonitoredItem *mon);
void UA_MonitoredItem_register(UA_Server *server, UA_MonitoredItem *mon);

/* Register sampling. Either by adding a repeated callback or by adding the
 * MonitoredItem to a linked list in the node. */
UA_StatusCode
UA_MonitoredItem_registerSampling(UA_Server *server, UA_MonitoredItem *mon);

void
UA_MonitoredItem_unregisterSampling(UA_Server *server, UA_MonitoredItem *mon);

UA_StatusCode
UA_MonitoredItem_setMonitoringMode(UA_Server *server, UA_MonitoredItem *mon,
                                   UA_MonitoringMode monitoringMode);

void
UA_MonitoredItem_sample(UA_Server *server, UA_MonitoredItem *mon);

/* Do not use the value after calling this. It will be moved to mon or freed. */
void
UA_MonitoredItem_processSampledValue(UA_Server *server, UA_MonitoredItem *mon,
                                     UA_DataValue *value);

UA_StatusCode
UA_MonitoredItem_removeLink(UA_Subscription *sub, UA_MonitoredItem *mon,
                            UA_UInt32 linkId);

UA_StatusCode
UA_MonitoredItem_addLink(UA_Subscription *sub, UA_MonitoredItem *mon,
                         UA_UInt32 linkId);

UA_StatusCode
UA_MonitoredItem_createDataChangeNotification(UA_Server *server, UA_MonitoredItem *mon,
                                              const UA_DataValue *value);

/* Remove entries until mon->maxQueueSize is reached. Sets infobits for lost
 * data if required. */
void UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon);

/****************/
/* Subscription */
/****************/

/* We use only a subset of the states defined in the standard */
typedef enum {
    UA_SUBSCRIPTIONSTATE_STOPPED = 0,
    UA_SUBSCRIPTIONSTATE_REMOVING,
    UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH, /* only keepalive */
    UA_SUBSCRIPTIONSTATE_ENABLED
} UA_SubscriptionState;

/* Subscriptions are managed in a server-wide linked list. If they are attached
 * to a Session, then they are additionaly in the per-Session linked-list. A
 * subscription is always generated for a Session. But the CloseSession Service
 * may keep Subscriptions intact beyond the Session lifetime. They can then be
 * re-bound to a new Session with the TransferSubscription Service. */
struct UA_Subscription {
    UA_DelayedCallback delayedFreePointers;
    LIST_ENTRY(UA_Subscription) serverListEntry;
    /* Ordered according to the priority byte and round-robin scheduling for
     * late subscriptions. See ua_session.h. Only set if session != NULL. */
    TAILQ_ENTRY(UA_Subscription) sessionListEntry;
    UA_Session *session; /* May be NULL if no session is attached. */
    UA_UInt32 subscriptionId;

    /* Settings */
    UA_UInt32 lifeTimeCount;
    UA_UInt32 maxKeepAliveCount;
    UA_Double publishingInterval; /* in ms */
    UA_UInt32 notificationsPerPublish;
    UA_Byte priority;

    /* Runtime information */
    UA_SubscriptionState state;
    UA_Boolean late;
    UA_Boolean wasTransferred; /* Set to true when this subscription was
                                * transferred to another session. Used to
                                * prevent incorrect diagnostic counter updates. */
    UA_StatusCode statusChange; /* If set, a notification is generated and the
                                 * Subscription is deleted within
                                 * UA_Subscription_publish. */
    UA_UInt32 nextSequenceNumber;
    UA_UInt32 currentKeepAliveCount;
    UA_UInt32 currentLifetimeCount;

    /* Publish Callback. Registered if id > 0. */
    UA_UInt64 publishCallbackId;

    /* Delayed callback to schedule publication of more notifications */
    UA_Boolean delayedCallbackRegistered;
    UA_DelayedCallback delayedMoreNotifications;

    /* MonitoredItems */
    UA_UInt32 lastMonitoredItemId; /* increase the identifiers */
    LIST_HEAD(, UA_MonitoredItem) monitoredItems;
    UA_UInt32 monitoredItemsSize;

    /* MonitoredItems that are sampled in every publish callback (with the
     * publish interval of the subscription) */
    LIST_HEAD(, UA_MonitoredItem) samplingMonitoredItems;

    /* Global list of notifications from the MonitoredItems */
    TAILQ_HEAD(, UA_Notification) notificationQueue;
    UA_UInt32 notificationQueueSize; /* Total queue size */
    UA_UInt32 dataChangeNotifications;
    UA_UInt32 eventNotifications;

    /* Retransmission Queue */
    NotificationMessageQueue retransmissionQueue;
    size_t retransmissionQueueSize;

    /* Statistics for the server diagnostics. The fields are defined according
     * to the SubscriptionDiagnosticsDataType (Part 5, §12.15). */
#ifdef UA_ENABLE_DIAGNOSTICS
    UA_NodeId ns0Id; /* Representation in the Session object */

    UA_UInt32 modifyCount;
    UA_UInt32 enableCount;
    UA_UInt32 disableCount;
    UA_UInt32 republishRequestCount;
    UA_UInt32 republishMessageCount;
    UA_UInt32 transferRequestCount;
    UA_UInt32 transferredToAltClientCount;
    UA_UInt32 transferredToSameClientCount;
    UA_UInt32 publishRequestCount;
    UA_UInt32 dataChangeNotificationsCount;
    UA_UInt32 eventNotificationsCount;
    UA_UInt32 notificationsCount;
    UA_UInt32 latePublishRequestCount;
    UA_UInt32 discardedMessageCount;
    UA_UInt32 monitoringQueueOverflowCount;
    UA_UInt32 eventQueueOverflowCount;
#endif
};

UA_Subscription * UA_Subscription_new(void);

void
UA_Subscription_delete(UA_Server *server, UA_Subscription *sub);

UA_StatusCode
Subscription_setState(UA_Server *server, UA_Subscription *sub,
                      UA_SubscriptionState state);

void
Subscription_resetLifetime(UA_Subscription *sub);

UA_Subscription *
getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId);

UA_MonitoredItem *
UA_Subscription_getMonitoredItem(UA_Subscription *sub,
                                 UA_UInt32 monitoredItemId);

void
UA_Subscription_publish(UA_Server *server, UA_Subscription *sub);

void
UA_Subscription_localPublish(UA_Server *server, UA_Subscription *sub);

void
UA_Subscription_resendData(UA_Server *server, UA_Subscription *sub);

UA_StatusCode
UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub,
                                            UA_UInt32 sequenceNumber);

void
UA_Session_ensurePublishQueueSpace(UA_Server *server, UA_Session *session);

/* Forward declaration for A&C used in ua_server_internal.h" */
struct UA_ConditionSource;
typedef struct UA_ConditionSource UA_ConditionSource;

/* Event Handling */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

#define UA_EVENTFILTER_MAXELEMENTS 64 /* Max operator elements */
#define UA_EVENTFILTER_MAXOPERANDS 64 /* Max operands per operator */
#define UA_EVENTFILTER_MAXSELECT   64 /* Max select clauses */

/* Static validation when the filter is registered */
UA_StatusCode
UA_SimpleAttributeOperandValidation(UA_Server *server,
                                    const UA_SimpleAttributeOperand *sao);

/* Static validation when the filter is registered */
UA_ContentFilterElementResult
UA_ContentFilterElementValidation(UA_Server *server, size_t operatorIndex,
                                  size_t operatorsCount,
                                  const UA_ContentFilterElement *ef);

/* If the sessionId, subscriptionId or monitoredItemId are non-NULL, they are
 * used to filter the subscriptions and monitoreditems that emit the event. */
UA_StatusCode
createEvent(UA_Server *server, const UA_EventDescription *ed,
            UA_ByteString *outEventId);

typedef struct {
    UA_Server *server;
    UA_Session *session;
    UA_EventDescription ed; /* shallow copy */
    UA_EventFilter filter;  /* shallow copy */

    /* Don't reread or regenerate values that have already been gotten during
     * the same filter evaluation */
    UA_KeyValueMap fieldCache;

    /* Generated / cached EventId */
    UA_ByteString eventId;
    UA_Byte eventIdBuf[16];

    /* <-- Variables used only by evaluateWhereClause --> */

    UA_Variant operatorResults[UA_EVENTFILTER_MAXELEMENTS];

    /* The operand stack contains temporary variants. Cleaned up after the
     * evaluation of each operator. */
    size_t top;
    UA_Variant operandStack[UA_EVENTFILTER_MAXOPERANDS];
} UA_FilterEvalContext;

/* The _reset method resets the filter between evaluations for different
 * MonitoredItems. The EventId is reset *only* if eventId.data != eventIdBuf.
 * This does not lead to memleaks and ensures we do not regenerate random
 * EventIds for the same event on different MonitoredItems. */
void UA_FilterEvalContext_init(UA_FilterEvalContext *ctx);
void UA_FilterEvalContext_reset(UA_FilterEvalContext *ctx);

UA_StatusCode
resolveSAO(UA_FilterEvalContext *ctx, const UA_SimpleAttributeOperand *sao,
           UA_Variant *out);

/* Retrieve or generate the unique EventId and cache it. Takes the EventId from
 * the EventDescription if explicitly set by the user. If successful,
 * ctx->eventId contains the cached EventId */
UA_StatusCode cacheEventId(UA_FilterEvalContext *ctx);

/* Evaluate content filter, exported only for unit testing */
UA_StatusCode
evaluateWhereClause(UA_FilterEvalContext *ctx);

/* Applies the select clause and resolves the result fields */
UA_StatusCode
evaluateSelectClause(UA_FilterEvalContext *ctx, UA_EventFieldList *efl);

#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */

/***********/
/* Helpers */
/***********/

/* Setting an integer value within bounds */
#define UA_BOUNDEDVALUE_SETWBOUNDS(BOUNDS, SRC, DST)   \
    do { \
        if(SRC > BOUNDS.max) DST = BOUNDS.max;         \
        else if(SRC < BOUNDS.min) DST = BOUNDS.min;    \
        else DST = SRC;                                \
    } while (0)

/* Logging
 * See a description of the tricks used in ua_session.h */
#define UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, LEVEL, SUB, MSG, ...)      \
    do {                                                                \
        if((SUB) && (SUB)->session) {                                   \
            UA_LOG_##LEVEL##_SESSION(LOGGER, (SUB)->session,            \
                                     "Subscription %" PRIu32 " | " MSG "%.0s", \
                                     (SUB)->subscriptionId, __VA_ARGS__); \
        } else {                                                        \
            UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SERVER,               \
                           "Subscription %" PRIu32 " | " MSG "%.0s",    \
                           (SUB) ? (SUB)->subscriptionId : 0, __VA_ARGS__); \
        }                                                               \
    } while(0)

#if UA_LOGLEVEL <= 100
# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, TRACE, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 200
# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, DEBUG, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 300
# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, INFO, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 400
# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, WARNING, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 500
# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, ERROR, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 600
# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, FATAL, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#endif /* UA_ENABLE_SUBSCRIPTIONS */

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_services.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017, 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015 (c) Sten Grüner
 *    Copyright 2014 (c) LEvertz
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Christian Fimmers
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */



_UA_BEGIN_DECLS

/* Services return whether they are "done". Otherwise no response is sent.
 * This then needs to be done asynchronously at a later time. */
typedef UA_Boolean (*UA_Service)(UA_Server*, UA_Session*,
                                 const void *request, void *response);

typedef void (*UA_ChannelService)(UA_Server*, UA_SecureChannel*,
                                  const void *request, void *response);

typedef struct {
    UA_UInt32 requestTypeId;
#ifdef UA_ENABLE_DIAGNOSTICS
    UA_UInt16 counterOffset;
#endif
    UA_Boolean sessionRequired;
    UA_Service serviceCallback;
    const UA_DataType *requestType;
    const UA_DataType *responseType;
} UA_ServiceDescription;

/* Returns NULL if none found */
UA_ServiceDescription * getServiceDescription(UA_UInt32 requestTypeId);

/** Discovery Service Set **/
UA_Boolean
Service_FindServers(UA_Server *server, UA_Session *session,
                    const UA_FindServersRequest *request,
                    UA_FindServersResponse *response);

UA_Boolean
Service_GetEndpoints(UA_Server *server, UA_Session *session,
                     const UA_GetEndpointsRequest *request,
                     UA_GetEndpointsResponse *response);

#ifdef UA_ENABLE_DISCOVERY

UA_Boolean
Service_RegisterServer(UA_Server *server, UA_Session *session,
                       const UA_RegisterServerRequest *request,
                       UA_RegisterServerResponse *response);

UA_Boolean
Service_RegisterServer2(UA_Server *server, UA_Session *session,
                        const UA_RegisterServer2Request *request,
                        UA_RegisterServer2Response *response);

# ifdef UA_ENABLE_DISCOVERY_MULTICAST

UA_Boolean
Service_FindServersOnNetwork(UA_Server *server, UA_Session *session,
                             const UA_FindServersOnNetworkRequest *request,
                             UA_FindServersOnNetworkResponse *response);

# endif /* UA_ENABLE_DISCOVERY_MULTICAST */

#endif /* UA_ENABLE_DISCOVERY */

/** SecureChannel Service Set **/
void
Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel* channel,
                          UA_OpenSecureChannelRequest *request,
                          UA_OpenSecureChannelResponse *response);

void
Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel);

/** Session Service Set **/
void
Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                      const UA_CreateSessionRequest *request,
                      UA_CreateSessionResponse *response);

void
Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
                        const UA_ActivateSessionRequest *request,
                        UA_ActivateSessionResponse *response);

void
Service_CloseSession(UA_Server *server, UA_SecureChannel *channel,
                     const UA_CloseSessionRequest *request,
                     UA_CloseSessionResponse *response);

UA_Boolean
Service_Cancel(UA_Server *server, UA_Session *session,
               const UA_CancelRequest *request,
               UA_CancelResponse *response);

/** NodeManagement Service Set **/
UA_Boolean
Service_AddNodes(UA_Server *server, UA_Session *session,
                 const UA_AddNodesRequest *request,
                 UA_AddNodesResponse *response);

UA_Boolean
Service_AddReferences(UA_Server *server, UA_Session *session,
                      const UA_AddReferencesRequest *request,
                      UA_AddReferencesResponse *response);

UA_Boolean
Service_DeleteNodes(UA_Server *server, UA_Session *session,
                    const UA_DeleteNodesRequest *request,
                    UA_DeleteNodesResponse *response);

UA_Boolean
Service_DeleteReferences(UA_Server *server, UA_Session *session,
                         const UA_DeleteReferencesRequest *request,
                         UA_DeleteReferencesResponse *response);

/** View Service Set **/
UA_Boolean
Service_Browse(UA_Server *server, UA_Session *session,
               const UA_BrowseRequest *request,
               UA_BrowseResponse *response);

UA_Boolean
Service_BrowseNext(UA_Server *server, UA_Session *session,
                   const UA_BrowseNextRequest *request,
                   UA_BrowseNextResponse *response);

UA_Boolean
Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
    const UA_TranslateBrowsePathsToNodeIdsRequest *request,
    UA_TranslateBrowsePathsToNodeIdsResponse *response);

UA_Boolean
Service_RegisterNodes(UA_Server *server, UA_Session *session,
                      const UA_RegisterNodesRequest *request,
                      UA_RegisterNodesResponse *response);

UA_Boolean
Service_UnregisterNodes(UA_Server *server, UA_Session *session,
                        const UA_UnregisterNodesRequest *request,
                        UA_UnregisterNodesResponse *response);

/** Query Service Set (not implemented) **/

/** Attribute Service Set **/
UA_Boolean
Service_Read(UA_Server *server, UA_Session *session,
             const UA_ReadRequest *request,
             UA_ReadResponse *response);

UA_Boolean
Operation_Read(UA_Server *server, UA_Session *session,
               UA_TimestampsToReturn ttr,
               const UA_ReadValueId *rvi, UA_DataValue *dv);

UA_Boolean
Service_Write(UA_Server *server, UA_Session *session,
              const UA_WriteRequest *request,
              UA_WriteResponse *response);

UA_Boolean
Operation_Write(UA_Server *server, UA_Session *session,
                const UA_WriteValue *wv, UA_StatusCode *result);

#ifdef UA_ENABLE_HISTORIZING
UA_Boolean
Service_HistoryRead(UA_Server *server, UA_Session *session,
                    const UA_HistoryReadRequest *request,
                    UA_HistoryReadResponse *response);

UA_Boolean
Service_HistoryUpdate(UA_Server *server, UA_Session *session,
                      const UA_HistoryUpdateRequest *request,
                      UA_HistoryUpdateResponse *response);
#endif

/** Method Service Set **/
#ifdef UA_ENABLE_METHODCALLS
UA_Boolean
Service_Call(UA_Server *server, UA_Session *session,
             const UA_CallRequest *request,
             UA_CallResponse *response);

UA_Boolean
Operation_CallMethod(UA_Server *server, UA_Session *session,
                     const UA_CallMethodRequest *request,
                     UA_CallMethodResult *result);
#endif

#ifdef UA_ENABLE_SUBSCRIPTIONS

/** MonitoredItem Service Set **/
UA_Boolean
Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_CreateMonitoredItemsRequest *request,
                             UA_CreateMonitoredItemsResponse *response);

UA_Boolean
Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_DeleteMonitoredItemsRequest *request,
                             UA_DeleteMonitoredItemsResponse *response);

UA_Boolean
Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_ModifyMonitoredItemsRequest *request,
                             UA_ModifyMonitoredItemsResponse *response);

UA_Boolean
Service_SetMonitoringMode(UA_Server *server, UA_Session *session,
                          const UA_SetMonitoringModeRequest *request,
                          UA_SetMonitoringModeResponse *response);

UA_Boolean
Service_SetTriggering(UA_Server *server, UA_Session *session,
                      const UA_SetTriggeringRequest *request,
                      UA_SetTriggeringResponse *response);

/** Subscription Service Set **/
UA_Boolean
Service_CreateSubscription(UA_Server *server, UA_Session *session,
                           const UA_CreateSubscriptionRequest *request,
                           UA_CreateSubscriptionResponse *response);

UA_Boolean
Service_ModifySubscription(UA_Server *server, UA_Session *session,
                           const UA_ModifySubscriptionRequest *request,
                           UA_ModifySubscriptionResponse *response);

UA_Boolean
Service_SetPublishingMode(UA_Server *server, UA_Session *session,
                          const UA_SetPublishingModeRequest *request,
                          UA_SetPublishingModeResponse *response);

UA_Boolean
Service_Publish(UA_Server *server, UA_Session *session,
                const UA_PublishRequest *request,
                UA_PublishResponse *response);

UA_Boolean
Service_Republish(UA_Server *server, UA_Session *session,
                  const UA_RepublishRequest *request,
                  UA_RepublishResponse *response);

UA_Boolean
Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
                            const UA_DeleteSubscriptionsRequest *request,
                            UA_DeleteSubscriptionsResponse *response);

UA_Boolean
Service_TransferSubscriptions(UA_Server *server, UA_Session *session,
                              const UA_TransferSubscriptionsRequest *request,
                              UA_TransferSubscriptionsResponse *response);

#endif /* UA_ENABLE_SUBSCRIPTIONS */

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_server_async.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick)
 *    Copyright 2025 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 * based on
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */




_UA_BEGIN_DECLS

struct UA_AsyncResponse;
typedef struct UA_AsyncResponse UA_AsyncResponse;

/* Synchronous and asynchronous operations go through the same initial control
 * flow. Only inside the read/write/call callback can the return code
 * UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY be used to signal asynchronous
 * processing.
 *
 * Also multiple operations come in at the same time from the same request. We
 * do all of this with as little overhead as possible for the case that all
 * operations are synchonous:
 *
 * The results-array for the response message is allocated "too long". After
 * every regular entry follows enough space for another array of
 * UA_AsyncOperation. This is used for ad-hoc asynchronous processing. Otherwise
 * the additional bytes at the end are simply ignored. */

/* REQUEST -> received over the network
 * DIRECT -> local C API call */
typedef enum {
    UA_ASYNCOPERATIONTYPE_CALL_REQUEST  = 0,
    UA_ASYNCOPERATIONTYPE_READ_REQUEST  = 1,
    UA_ASYNCOPERATIONTYPE_WRITE_REQUEST = 2,
    UA_ASYNCOPERATIONTYPE_CALL_DIRECT   = (0 + 4),
    UA_ASYNCOPERATIONTYPE_READ_DIRECT   = (1 + 4),
    UA_ASYNCOPERATIONTYPE_WRITE_DIRECT  = (2 + 4)
} UA_AsyncOperationType;

/* A single operation (of a larger request) */
typedef struct UA_AsyncOperation {
    TAILQ_ENTRY(UA_AsyncOperation) pointers;
    UA_AsyncOperationType asyncOperationType;

    union {
        /* The operation is part of a service request */
        UA_AsyncResponse *response;

        /* The operation was called directly */
        struct {
            UA_DateTime timeout;
            void *context;
            union {
                UA_ServerAsyncReadResultCallback read;
                UA_ServerAsyncWriteResultCallback write;
                UA_ServerAsyncMethodResultCallback call;
            } method;
        } callback;
    } handling;

    /* For service requests: the pointer to the output value in the response
     * For direct calls: the memory for the output value */
    union {
        UA_CallMethodResult *call;
        UA_StatusCode *write;
        UA_DataValue *read;
        UA_CallMethodResult directCall;
        UA_StatusCode directWrite;
        UA_DataValue directRead;
    } output;

    union {
        /* Forward the pointer to writeValue to the operationCallback. So the
         * pointer is stable and the memory location unique, also when the
         * original request has been freed. But this uses a shallow copy. So
         * don't access the writeValue after the operationCallback. */
        UA_WriteValue writeValue;
    } context;
} UA_AsyncOperation;

struct UA_AsyncResponse {
    TAILQ_ENTRY(UA_AsyncResponse) pointers; /* Insert new at the end */

    UA_UInt32 requestId;
    UA_UInt32 requestHandle;
    UA_DateTime timeout;
    UA_NodeId sessionId;
    UA_UInt32 opCountdown; /* Counter for outstanding operations. The AR can
                            * only be deleted when all have returned. */

    const UA_DataType *responseType;
    union {
        UA_CallResponse callResponse;
        UA_ReadResponse readResponse;
        UA_WriteResponse writeResponse;
    } response;
};

typedef struct {
    /* Forward the request id here as the "UA_Service" method signature does not
     * contain it */
    UA_UInt32 currentRequestId;
    UA_UInt32 currentRequestHandle;

    /* Async responses */
    TAILQ_HEAD(, UA_AsyncResponse) waitingResponses;
    TAILQ_HEAD(, UA_AsyncResponse) readyResponses;

    /* Async operations (some direct, some part of an async response) */
    TAILQ_HEAD(, UA_AsyncOperation) waitingOps;
    TAILQ_HEAD(, UA_AsyncOperation) readyOps;
    size_t opsCount; /* Both waiting and ready */

    UA_UInt64 checkTimeoutCallbackId; /* Registered repeated callbacks */

    UA_DelayedCallback dc; /* Delayed callback to have the main thread handle
                            * ready operations and responses */
} UA_AsyncManager;

void UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server);
void UA_AsyncManager_start(UA_AsyncManager *am, UA_Server *server);
void UA_AsyncManager_stop(UA_AsyncManager *am, UA_Server *server);
void UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server);

/* Cancel all outstanding operations for matching session+requestHandle.
 * Then sends out the responses with a StatusCode. */
UA_UInt32
UA_AsyncManager_cancel(UA_Server *server, UA_Session *session, UA_UInt32 requestHandle);

/* Internal async API */
UA_StatusCode
read_async(UA_Server *server, UA_Session *session, const UA_ReadValueId *operation,
           UA_TimestampsToReturn ttr, UA_ServerAsyncReadResultCallback callback,
           void *context, UA_UInt32 timeout);

UA_StatusCode
write_async(UA_Server *server, UA_Session *session, const UA_WriteValue *operation,
            UA_ServerAsyncWriteResultCallback callback, void *context,
            UA_UInt32 timeout);

UA_StatusCode
call_async(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *operation,
           UA_ServerAsyncMethodResultCallback callback, void *context, UA_UInt32 timeout);

void
async_cancel(UA_Server *server, void *context, UA_StatusCode status,
             UA_Boolean cancelSynchronous);

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_server_internal.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick)
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2021-2025 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2022 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 */


#define UA_INTERNAL


_UA_BEGIN_DECLS

#ifdef UA_ENABLE_SUBSCRIPTIONS

typedef struct {
    UA_MonitoredItem monitoredItem;
    void *context;
    union {
        UA_Server_DataChangeNotificationCallback dataChangeCallback;
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        UA_Server_EventNotificationCallback eventCallback;
#endif
    } callback;

    /* For Event-MonitoredItems only. The value fields are overwritten before
     * each callback. They can contain stray pointers between callbacks. So
     * don't clean up the value fields. */
    UA_KeyValueMap eventFields;
} UA_LocalMonitoredItem;

#endif /* !UA_ENABLE_SUBSCRIPTIONS */

/********************/
/* GDS Transaction  */
/********************/

typedef enum {
    UA_GDSTRANSACTIONSTATE_FRESH,
    UA_GDSTRANSACTIONSTATE_PENDING,
} UA_GDSTransactionState;

typedef struct {
    UA_ByteString certificate;
    UA_ByteString privateKey;
    UA_NodeId certificateGroup;
    UA_NodeId certificateType;
} UA_GDSCertificateInfo;

typedef struct {
    UA_Server *server;
    UA_NodeId sessionId;
    UA_GDSTransactionState state;

    UA_ByteString localCsrCertificate;

    size_t certGroupSize;
    UA_CertificateGroup *certGroups;

    size_t certificateInfosSize;
    UA_GDSCertificateInfo *certificateInfos;

    /* Callback to close all SecureChannels after calling applyChanges
     * and freeing the transaction. */
    UA_DelayedCallback dc;
} UA_GDSTransaction;

UA_StatusCode
UA_GDSTransaction_init(UA_GDSTransaction *transaction,
                       UA_Server *server,
                       const UA_NodeId sessionId);

/* Returns the appropriate CertificateGroup from the transaction.
 * If the CertificateGroup does not exist in the transaction, it will be created. */
UA_CertificateGroup*
UA_GDSTransaction_getCertificateGroup(UA_GDSTransaction *transaction,
                                      const UA_CertificateGroup *certGroup);

UA_StatusCode
UA_GDSTransaction_addCertificateInfo(UA_GDSTransaction *transaction,
                                     const UA_NodeId certificateGroupId,
                                     const UA_NodeId certificateTypeId,
                                     const UA_ByteString *certificate,
                                     const UA_ByteString *privateKey);

void
UA_GDSTransaction_clear(UA_GDSTransaction *transaction);

void
UA_GDSTransaction_delete(UA_GDSTransaction *transaction);

/********************/
/*   GDS Manager    */
/********************/

typedef struct {
    /* Transaction for certificate management */
    UA_GDSTransaction transaction;
    /* Contains context information necessary for reading and writing the TrustList as a file type */
    void *fileInfoContext;
    /* Holds the ID for the repeated callback that verifies the presence of sessions
     * with an active transaction or an open trust list */
    UA_UInt64 checkSessionCallbackId;
} UA_GDSManager;

void
UA_GDSManager_clear(UA_GDSManager *gdsManager);

/********************/
/* Server Component */
/********************/

/* ServerComponents have an explicit lifecycle. But they can only be started
 * when the underlying server is started. The starting/stopping of
 * ServerComponents is asynchronous. That is, they might require several
 * iterations of the EventLoop to finish starting/stopping.
 *
 * ServerComponents can only be deleted when they are STOPPED. The server will
 * not fully shut down as long as there is a component remaining. */

typedef struct UA_ServerComponent {
    UA_UInt64 identifier;
    UA_String name;
    ZIP_ENTRY(UA_ServerComponent) treeEntry;
    UA_LifecycleState state;
    UA_Server *server; /* Every ServerComponent has a backpointer to the server */

    /* Starting fails if the server is not also already started */
    UA_StatusCode (*start)(struct UA_ServerComponent *sc, UA_Server *server);

    /* Stopping is asynchronous and might need a few iterations of the main-loop
     * to succeed. */
    void (*stop)(struct UA_ServerComponent *sc);

    /* Clean up the ServerComponent. Can fail if it is not stopped. This does
     * not free the memory and does not remove from the ziptree. */
    UA_StatusCode (*clear)(struct UA_ServerComponent *sc);

    /* To be set by the server. So the component can notify the server about
     * asynchronous state changes. */
    void (*notifyState)(struct UA_ServerComponent *sc,
                        UA_LifecycleState state);
} UA_ServerComponent;

enum ZIP_CMP
cmpServerComponent(const UA_UInt64 *a, const UA_UInt64 *b);

typedef ZIP_HEAD(UA_ServerComponentTree, UA_ServerComponent) UA_ServerComponentTree;

ZIP_FUNCTIONS(UA_ServerComponentTree, UA_ServerComponent, treeEntry,
              UA_UInt64, identifier, cmpServerComponent)

/* Assigns the identifier if the pointer is non-NULL.
 * Starts the component if the server is started. */
void
addServerComponent(UA_Server *server, UA_ServerComponent *sc,
                   UA_UInt64 *identifier);

UA_ServerComponent *
getServerComponentByName(UA_Server *server, UA_String name);

/********************/
/* Server Structure */
/********************/

typedef struct session_list_entry {
    UA_DelayedCallback cleanupCallback;
    LIST_ENTRY(session_list_entry) pointers;
    UA_Session session;
} session_list_entry;

struct UA_Server {
    /* Config */
    UA_ServerConfig config;

    /* Runtime state */
    UA_DateTime startTime;
    UA_DateTime endTime; /* Zeroed out. If a time is set, then the server shuts
                          * down once the time has been reached */

    UA_LifecycleState state;
    UA_UInt64 houseKeepingCallbackId;

    UA_UInt64 serverComponentIds; /* Counter to assign ids from */
    UA_ServerComponentTree serverComponents;

    UA_AsyncManager asyncManager;

    /* Custom datatypes that are internally created and cleaned up at the end of
     * the server lifecycle. The next->pointer points to the server config. So
     * we can use customTypes_internal as the universal entry. */
    UA_DataTypeArray *customTypes_internal;
    size_t customTypes_internalSize;

    /* Session Management */
    LIST_HEAD(session_list, session_list_entry) sessions;
    UA_UInt32 sessionCount;
    UA_UInt32 activeSessionCount;

    /* Session for local access to the services for upkeep and the C API. Comes
     * equipped with all possible access rights (Session Id: 1). */
    UA_Session adminSession;

    /* SecureChannels */
    TAILQ_HEAD(, UA_SecureChannel) channels;
    UA_UInt32 lastChannelId;
    UA_UInt32 lastTokenId;

    /* Namespaces */
    size_t namespacesSize;
    UA_String *namespaces;

    /* For bootstrapping, omit some consistency checks, creating a reference to
     * the parent and member instantiation */
    UA_Boolean bootstrapNS0;

    /* Subscriptions */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* The admin session is initialized with a special subscription. This
     * subscription generates delayed callbacks with notifications for local
     * processing. */
    UA_Subscription *adminSubscription;

    size_t subscriptionsSize;  /* Number of active subscriptions */
    size_t monitoredItemsSize; /* Number of active monitored items */
    LIST_HEAD(, UA_Subscription) subscriptions; /* All subscriptions in the
                                                 * server. They may be detached
                                                 * from a session. */
    UA_UInt32 lastSubscriptionId; /* To generate unique SubscriptionIds */

# ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
    LIST_HEAD(, UA_ConditionSource) conditionSources;
# endif
#endif

#if UA_MULTITHREADING >= 100
    UA_Lock serviceMutex;
#endif

    /* Statistics */
    UA_SecureChannelStatistics secureChannelStatistics;
    UA_ServerDiagnosticsSummaryDataType serverDiagnosticsSummary;

    /* GDS Manager for certificate management */
    UA_GDSManager gdsManager;
};

/* In case the configuration was updated. Make the ->next pointer in the
 * internal customTypes point into the configuration. */
const UA_DataTypeArray *
serverCustomTypes(UA_Server *server);

/***********************/
/* References Handling */
/***********************/

enum ZIP_CMP
cmpRefTargetId(const void *a, const void *b);

enum ZIP_CMP
cmpRefTargetName(const void *a, const void *b);

/* Static inline methods for tree handling */
typedef ZIP_HEAD(UA_ReferenceIdTree, UA_ReferenceTargetTreeElem) UA_ReferenceIdTree;
ZIP_FUNCTIONS(UA_ReferenceIdTree, UA_ReferenceTargetTreeElem, idTreeEntry,
              UA_ReferenceTargetTreeElem, target, cmpRefTargetId)

typedef ZIP_HEAD(UA_ReferenceNameTree, UA_ReferenceTargetTreeElem) UA_ReferenceNameTree;
ZIP_FUNCTIONS(UA_ReferenceNameTree, UA_ReferenceTargetTreeElem, nameTreeEntry,
              UA_ReferenceTarget, target, cmpRefTargetName)

/**************************/
/* SecureChannel Handling */
/**************************/

/* Session and channel can be NULL, only used for logging.
 * Ad can be NULL, then the ApplicationUri is not checked. */
UA_StatusCode
validateCertificate(UA_Server *server, UA_CertificateGroup *cg,
                    UA_SecureChannel *channel, UA_Session *session,
                    const char *logPrefix,
                    const UA_ApplicationDescription *ad,
                    const UA_ByteString certificate);

void
serverNetworkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                      void *application, void **connectionContext,
                      UA_ConnectionState state,
                      const UA_KeyValueMap *params,
                      UA_ByteString msg);

UA_StatusCode
sendServiceFault(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId,
                 UA_UInt32 requestHandle, UA_StatusCode statusCode);

/* Validate the remote certificate received in the OPN message and create the
 * SecureChannel context. This is needed before OPN is decrypted. */
UA_StatusCode
processOPN_AsymHeader(void *application, UA_SecureChannel *channel,
                      const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);

/* Gets the a pointer to the context of a security policy supported by the
 * server matched by the security policy uri. */
UA_SecurityPolicy *
getSecurityPolicyByUri(const UA_Server *server,
                       const UA_String *securityPolicyUri);

/* Get only the #None or #Basic256Sha256 postfix of a SecurityPolicyUri */
UA_String
securityPolicyUriPostfix(const UA_String uri);

UA_SecurityPolicy *
getSecurityPolicyByPostfix(const UA_Server *server,
                           const UA_String uriPostfix);

void
notifySecureChannel(UA_Server *server, UA_SecureChannel *channel,
                    UA_ApplicationNotificationType type);

/********************/
/* Session Handling */
/********************/

UA_StatusCode
getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
                   size_t *foundIndex);

UA_StatusCode
getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
                    UA_String *foundUri);

UA_StatusCode
getBoundSession(UA_Server *server, const UA_SecureChannel *channel,
                const UA_NodeId *token, UA_Session **session);

UA_StatusCode
UA_Session_create(UA_Server *server, UA_SecureChannel *channel,
                  const UA_CreateSessionRequest *request,
                  UA_Session **session);

void
UA_Session_remove(UA_Server *server, UA_Session *session,
                  UA_ShutdownReason shutdownReason);

void
cleanupSessions(UA_Server *server, UA_DateTime nowMonotonic);

UA_Session *
getSessionByToken(UA_Server *server, const UA_NodeId *token);

UA_Session *
getSessionById(UA_Server *server, const UA_NodeId *sessionId);

/*****************/
/* Node Handling */
/*****************/

/* Calls the callback with the node retrieved from the nodestore on top of the
 * stack. Either a copy or the original node for in-situ editing. Depends on
 * multithreading and the nodestore.*/
typedef UA_StatusCode (*UA_EditNodeCallback)(UA_Server*, UA_Session*,
                                             UA_Node *node, void*);
UA_StatusCode
editNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
         UA_UInt32 attributeMask, UA_ReferenceTypeSet references,
         UA_BrowseDirection referenceDirections,
         UA_EditNodeCallback callback, void *data);

/* Search for a child with a given browseNamee. Returns the first match. Does
 * not touch outChildNodeId if no child is found. */
UA_StatusCode
findChildByBrowsename(UA_Server *server, UA_Session *session,
                      const UA_NodeId parentId, UA_NodeClass nodeClassMask,
                      const UA_Byte refType, const UA_NodeId refTypeId,
                      const UA_QualifiedName *browseName,
                      UA_NodeId *outChildNodeId);

/*********************/
/* Utility Functions */
/*********************/

void setServerLifecycleState(UA_Server *server, UA_LifecycleState state);

void setupNs1Uri(UA_Server *server);
UA_UInt16 addNamespace(UA_Server *server, const UA_String name);

UA_Boolean
UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head);

/* Recursively searches "upwards" in the tree following specific reference types */
UA_Boolean
isNodeInTree(UA_Server *server, const UA_NodeId *leafNode,
             const UA_NodeId *nodeToFind, const UA_ReferenceTypeSet *relevantRefs);

/* Convenience function with just a single ReferenceTypeIndex */
UA_Boolean
isNodeInTree_singleRef(UA_Server *server, const UA_NodeId *leafNode,
                       const UA_NodeId *nodeToFind, const UA_Byte relevantRefTypeIndex);

/* Returns an array with the hierarchy of nodes. The start nodes can be returned
 * as well. The returned array starts at the leaf and continues "upwards" or
 * "downwards". Duplicate entries are removed. */
UA_StatusCode
browseRecursive(UA_Server *server, size_t startNodesSize, const UA_NodeId *startNodes,
                UA_BrowseDirection browseDirection, const UA_ReferenceTypeSet *refTypes,
                UA_UInt32 nodeClassMask, UA_Boolean includeStartNodes,
                size_t *resultsSize, UA_ExpandedNodeId **results);

/* Get the bitfield indices of a ReferenceType and possibly its subtypes.
 * refType must point to a ReferenceTypeNode. */
UA_StatusCode
referenceTypeIndices(UA_Server *server, const UA_NodeId *refType,
                     UA_ReferenceTypeSet *indices, UA_Boolean includeSubtypes);

/* Returns the recursive type hierarchy for an Object/ObjectType or
 * Variable/VariableType. Does not return interfaces. */
UA_StatusCode
getTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *leafNode,
                             UA_Boolean includeLeaf, UA_NodeId **typeHierarchy,
                             size_t *typeHierarchySize);

/* Returns the recursive interface hierarchy of the node */
UA_StatusCode
getAllInterfaces(UA_Server *server, const UA_NodeId *objectNode,
                 UA_NodeId **interfaceNodes, size_t *interfaceNodesSize);

#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS

UA_StatusCode
UA_getConditionId(UA_Server *server, const UA_NodeId *conditionNodeId,
                  UA_NodeId *outConditionId);

void
UA_ConditionList_delete(UA_Server *server);

UA_Boolean
isConditionOrBranch(UA_Server *server,
                    const UA_NodeId *condition,
                    const UA_NodeId *conditionSource,
                    UA_Boolean *isCallerAC);

#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */

/* Returns the first "HasTypeDefinition" or "HasSubtype" reference to the
 * (parent) type. Some types have very many instances. If the type is created
 * ad-hoc by the Nodestore, the attributeMask and reference characterization can
 * be used to return only relevant attributes/references. */
const UA_Node *
getNodeType(UA_Server *server, const UA_NodeHead *nodeHead,
            UA_UInt32 attributeMask, UA_ReferenceTypeSet references,
            UA_BrowseDirection referenceDirections);

/* Returns whether the response is done (async call or not) */
UA_Boolean
processRequest(UA_Server *server, UA_SecureChannel *channel,
               UA_UInt32 requestId, UA_ServiceDescription *sd,
               const UA_Request *request, UA_Response *response);

UA_StatusCode
sendResponse(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId,
             UA_Response *response, const UA_DataType *responseType);

typedef void (*UA_ServiceOperation)(UA_Server *server, UA_Session *session,
                                    const void *context,
                                    const void *requestOperation,
                                    void *responseOperation);

/* Many services come as an array of operations. This function generalizes the
 * processing of the operations. */
UA_StatusCode
allocProcessServiceOperations(UA_Server *server, UA_Session *session,
                              UA_ServiceOperation operationCallback,
                              const void *context,
                              const size_t *requestOperations,
                              const UA_DataType *requestOperationsType,
                              size_t *responseOperations,
                              const UA_DataType *responseOperationsType)
    UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT;

/*********************/
/* Locking/Unlocking */
/*********************/

/* In order to prevent deadlocks between the EventLoop mutex and the
 * server-mutex, we always take the EventLoop mutex first. */

void lockServer(UA_Server *server);
void unlockServer(UA_Server *server);

/******************************************/
/* Internal function calls, without locks */
/******************************************/
UA_StatusCode
deleteNode(UA_Server *server, const UA_NodeId nodeId,
           UA_Boolean deleteReferences);

UA_StatusCode
addRef(UA_Server *server, const UA_NodeId sourceId,
       const UA_NodeId referenceTypeId, const UA_NodeId targetId,
       UA_Boolean forward);

UA_StatusCode
deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                const UA_NodeId referenceTypeId, UA_Boolean isForward,
                const UA_ExpandedNodeId targetNodeId,
                UA_Boolean deleteBidirectional);

UA_StatusCode
addRefWithSession(UA_Server *server, UA_Session *session, const UA_NodeId *sourceId,
                  const UA_NodeId *referenceTypeId, const UA_NodeId *targetId,
                  UA_Boolean forward);

UA_StatusCode
setVariableNode_callbackValueSource(UA_Server *server, const UA_NodeId nodeId,
                                    const UA_CallbackValueSource evs);

UA_StatusCode
setVariableNode_internalValueSource(UA_Server *server, const UA_NodeId nodeId,
                                    const UA_DataValue *value,
                                    const UA_ValueSourceNotifications *notifications);

UA_StatusCode
setMethodNode_callback(UA_Server *server, const UA_NodeId methodNodeId,
                       UA_MethodCallback methodCallback);

UA_StatusCode
setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                     UA_NodeTypeLifecycle lifecycle);

UA_StatusCode
writeAttribute(UA_Server *server, UA_Session *session,
               const UA_NodeId *nodeId, const UA_AttributeId attributeId,
               const void *attr, const UA_DataType *attr_type);

#define UA_WRITEATTRIBUTEFUNCS(ATTR, ATTRID, TYPE, TYPENAME)            \
    static UA_INLINE UA_StatusCode                                      \
    write##ATTR##Attribute(UA_Server *server, const UA_NodeId nodeId,   \
                           const TYPE value) {                          \
        return writeAttribute(server, &server->adminSession, &nodeId,   \
                              ATTRID, &value, &UA_TYPES[UA_TYPES_##TYPENAME]); \
    }                                                                   \
    static UA_INLINE UA_StatusCode                                      \
    write##ATTR##AttributeWithSession(UA_Server *server, UA_Session *session, \
                                      const UA_NodeId nodeId, const TYPE value) { \
        return writeAttribute(server, session, &nodeId, ATTRID, &value, \
                              &UA_TYPES[UA_TYPES_##TYPENAME]);          \
    }

static UA_INLINE UA_StatusCode
writeValueAttribute(UA_Server *server, const UA_NodeId nodeId,
                    const UA_Variant *value) {
    return writeAttribute(server, &server->adminSession, &nodeId,
                          UA_ATTRIBUTEID_VALUE, value, &UA_TYPES[UA_TYPES_VARIANT]);
}

UA_WRITEATTRIBUTEFUNCS(IsAbstract, UA_ATTRIBUTEID_ISABSTRACT, UA_Boolean, BOOLEAN)
UA_WRITEATTRIBUTEFUNCS(ValueRank, UA_ATTRIBUTEID_VALUERANK, UA_Int32, INT32)
UA_WRITEATTRIBUTEFUNCS(AccessLevel, UA_ATTRIBUTEID_ACCESSLEVEL, UA_Byte, BYTE)
UA_WRITEATTRIBUTEFUNCS(MinimumSamplingInterval, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
                       UA_Double, DOUBLE)

UA_DataValue
readWithSession(UA_Server *server, UA_Session *session,
                const UA_ReadValueId *item,
                UA_TimestampsToReturn timestampsToReturn);

UA_StatusCode
readWithReadValue(UA_Server *server, const UA_NodeId *nodeId,
                  const UA_AttributeId attributeId, void *v);

UA_StatusCode
readObjectProperty(UA_Server *server, const UA_NodeId objectId,
                   const UA_QualifiedName propertyName,
                   UA_Variant *value);

UA_BrowsePathResult
translateBrowsePathToNodeIds(UA_Server *server, const UA_BrowsePath *browsePath);

/* Returns the "best" configured SecurityPolicy with encryption. The _NONE type
 * is the wildcard for any SecurityPolicy. */
UA_SecurityPolicy *
getDefaultEncryptedSecurityPolicy(UA_Server *server,
                                  UA_SecurityPolicyType type);

/* If the channel is non-NULL, then only compatible endpoints are returned.
 * Depending on ECC/RSA for the SecurityPolicy of the existing channel. */
UA_StatusCode
setCurrentEndpointsArray(UA_Server *server, const UA_String endpointUrl,
                         UA_String *profileUris, size_t profileUrisSize,
                         UA_EndpointDescription **arr, size_t *arrSize);

UA_BrowsePathResult
browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
                           size_t browsePathSize, const UA_QualifiedName *browsePath);

UA_StatusCode
writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
                    const UA_QualifiedName propertyName, const UA_Variant value);

UA_StatusCode
writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
                                     const UA_QualifiedName propertyName,
                                     const void *value, const UA_DataType *type);

UA_StatusCode
getNodeContext(UA_Server *server, UA_NodeId nodeId, void **nodeContext);

UA_StatusCode
setNodeContext(UA_Server *server, UA_NodeId nodeId, void *nodeContext);

void
removeCallback(UA_Server *server, UA_UInt64 callbackId);

UA_StatusCode
changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                               UA_Double interval_ms);

UA_StatusCode
addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                    void *data, UA_Double interval_ms, UA_UInt64 *callbackId);

#ifdef UA_ENABLE_DISCOVERY
UA_ServerComponent * UA_DiscoveryManager_new(void);
#endif

UA_ServerComponent * UA_BinaryProtocolManager_new(UA_Server *server);


#ifdef UA_ENABLE_PUBSUB
UA_ServerComponent * UA_PubSubManager_new(UA_Server *server);
#endif

/***********/
/* RefTree */
/***********/

/* A RefTree is a sorted set of NodeIds that ensures we consider each node just
 * once. It holds a single array for both the ExpandedNodeIds and the entries of
 * a tree-structure for fast lookup. A single realloc operation (with some
 * pointer repairing) can be used to increase the capacity of the RefTree.
 *
 * When the RefTree is complete, the tree-part at the end of the targets array
 * can be ignored / cut away to use it as a simple ExpandedNodeId array.
 *
 * The layout of the targets array is as follows:
 *
 * | Targets [ExpandedNodeId, n times] | Tree [RefEntry, n times] | */

#define UA_REFTREE_INITIAL_SIZE 16

typedef struct RefEntry {
    ZIP_ENTRY(RefEntry) zipfields;
    const UA_ExpandedNodeId *target;
    UA_UInt32 targetHash; /* Hash of the target nodeid */
} RefEntry;

ZIP_HEAD(RefHead, RefEntry);
typedef struct RefHead RefHead;

typedef struct {
    UA_ExpandedNodeId *targets;
    RefHead head;
    size_t capacity; /* available space */
    size_t size;     /* used space */
} RefTree;

UA_StatusCode UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
RefTree_init(RefTree *rt);

void RefTree_clear(RefTree *rt);

UA_StatusCode UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
RefTree_addNodeId(RefTree *rt, const UA_NodeId *target, UA_Boolean *duplicate);

UA_Boolean
RefTree_contains(RefTree *rt, const UA_ExpandedNodeId *target);

UA_Boolean
RefTree_containsNodeId(RefTree *rt, const UA_NodeId *target);

/* Browse recursive starting from all nodes already in the rt. Add matching
 * targets to the rt and continue. Does not clean up the rt in case of an
 * error. */
UA_StatusCode
browseRecursiveRefTree(UA_Server *server, RefTree *rt,
                       UA_BrowseDirection browseDirection,
                       const UA_ReferenceTypeSet *refTypes,
                       UA_UInt32 nodeClassMask);

/***************************************/
/* Check Information Model Consistency */
/***************************************/

UA_StatusCode
readValueAttribute(UA_Server *server, UA_Session *session,
                   const UA_VariableNode *vn, UA_DataValue *v);

/* Test whether the value matches a variable definition given by
 * - datatype
 * - valuerank
 * - array dimensions.
 * Sometimes it can be necessary to transform the content of the value, e.g.
 * byte array to bytestring or uint32 to some enum. If editableValue is non-NULL,
 * we try to create a matching variant that points to the original data.
 *
 * The reason is set whenever the return value is false */
UA_Boolean
compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId,
                UA_Int32 targetValueRank, size_t targetArrayDimensionsSize,
                const UA_UInt32 *targetArrayDimensions, const UA_Variant *value,
                const UA_NumericRange *range, const char **reason);

/* Is the DataType compatible */
UA_Boolean
compatibleDataTypes(UA_Server *server, const UA_NodeId *dataType,
                    const UA_NodeId *constraintDataType);

/* Set to the target type if compatible */
void
adjustValueType(UA_Server *server, UA_Variant *value,
                const UA_NodeId *targetDataTypeId);

/* Is the Value compatible with the DataType? Can perform additional checks
 * compared to compatibleDataTypes. */
UA_Boolean
compatibleValueDataType(UA_Server *server, const UA_DataType *dataType,
                        const UA_NodeId *constraintDataType);


UA_Boolean
compatibleArrayDimensions(size_t constraintArrayDimensionsSize,
                          const UA_UInt32 *constraintArrayDimensions,
                          size_t testArrayDimensionsSize,
                          const UA_UInt32 *testArrayDimensions);

UA_Boolean
compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimensionsSize,
                               const UA_UInt32 *targetArrayDimensions);

UA_Boolean
compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session,
                                   UA_Int32 valueRank, size_t arrayDimensionsSize);

UA_Boolean
compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank);

struct BrowseOpts {
    UA_UInt32 maxReferences;
    UA_Boolean recursive;
};

void
Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxrefs,
                 const UA_BrowseDescription *descr, UA_BrowseResult *result);

/* External data either from a datasource callback or with a _beforeRead
 * callback where fresh values get switched in on demand. Variables with an
 * external data source require monitoring with a sampling interval. As we
 * cannot just hook into the write service to get all changes. */
UA_Boolean
VariableNode_externalDataSource(const UA_VariableNode *vn);

/************/
/* AddNodes */
/************/

UA_StatusCode
addNode(UA_Server *server, const UA_NodeClass nodeClass,
        const UA_NodeId requestedNewNodeId,
        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
        const void *attr, const UA_DataType *attributeType,
        void *nodeContext, UA_NodeId *outNewNodeId);

UA_StatusCode
addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
              const UA_QualifiedName browseName,
              const UA_MethodAttributes *attr, UA_MethodCallback method,
              size_t inputArgumentsSize, const UA_Argument *inputArguments,
              const UA_NodeId inputArgumentsRequestedNewNodeId,
              UA_NodeId *inputArgumentsOutNewNodeId,
              size_t outputArgumentsSize, const UA_Argument *outputArguments,
              const UA_NodeId outputArgumentsRequestedNewNodeId,
              UA_NodeId *outputArgumentsOutNewNodeId,
              void *nodeContext, UA_NodeId *outNewNodeId);

UA_StatusCode
addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
              const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
              const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
              const UA_NodeId typeDefinition, const void *attr,
              const UA_DataType *attributeType, void *nodeContext,
              UA_NodeId *outNewNodeId);

/* Creates a new node in the nodestore. */
UA_StatusCode
addNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
            const UA_AddNodesItem *item, UA_NodeId *outNewNodeId);

/* Check the reference to the parent node; Add references. */
UA_StatusCode
addNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
                const UA_NodeId *typeDefinitionId);

/* Type-check type-definition; Run the constructors */
UA_StatusCode
addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId);

/**********************/
/* Create Namespace 0 */
/**********************/

UA_StatusCode initNS0(UA_Server *server);

/* Connect data sources to existing NS0 nodes */
UA_StatusCode initNS0_dataSources(UA_Server *server);

#ifdef UA_ENABLE_GDS_PUSHMANAGEMENT
UA_StatusCode
initNS0PushManagement(UA_Server *server);
#endif


#ifdef UA_ENABLE_DIAGNOSTICS
void createSessionObject(UA_Server *server, UA_Session *session);

void createSubscriptionObject(UA_Server *server, UA_Session *session,
                              UA_Subscription *sub);

UA_StatusCode
readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp,
                const UA_NumericRange *range, UA_DataValue *value);

UA_StatusCode
readSubscriptionDiagnosticsArray(UA_Server *server,
                                 const UA_NodeId *sessionId, void *sessionContext,
                                 const UA_NodeId *nodeId, void *nodeContext,
                                 UA_Boolean sourceTimestamp,
                                 const UA_NumericRange *range, UA_DataValue *value);

UA_StatusCode
readSessionDiagnosticsArray(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *nodeId, void *nodeContext,
                            UA_Boolean sourceTimestamp,
                            const UA_NumericRange *range, UA_DataValue *value);

UA_StatusCode
readSessionSecurityDiagnostics(UA_Server *server,
                               const UA_NodeId *sessionId, void *sessionContext,
                               const UA_NodeId *nodeId, void *nodeContext,
                               UA_Boolean sourceTimestamp,
                               const UA_NumericRange *range, UA_DataValue *value);
#endif

/***************************/
/* Nodestore Access Macros */
/***************************/

#define UA_NODESTORE_NEW(server, nodeClass)                             \
    server->config.nodestore->newNode(server->config.nodestore, nodeClass)

#define UA_NODESTORE_DELETE(server, node)                               \
    server->config.nodestore->deleteNode(server->config.nodestore, node)

/* Get the node with all attributes and references */
static UA_INLINE const UA_Node *
UA_NODESTORE_GET(UA_Server *server, const UA_NodeId *nodeId) {
    return server->config.nodestore->
        getNode(server->config.nodestore, nodeId, UA_NODEATTRIBUTESMASK_ALL,
                UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
}

/* Get the editable node with all attributes and references */
static UA_INLINE UA_Node *
UA_NODESTORE_GET_EDIT(UA_Server *server, const UA_NodeId *nodeId) {
    return server->config.nodestore->
        getEditNode(server->config.nodestore, nodeId,
                    UA_NODEATTRIBUTESMASK_ALL, UA_REFERENCETYPESET_ALL,
                    UA_BROWSEDIRECTION_BOTH);
}

/* Get the node with all attributes and references */
static UA_INLINE const UA_Node *
UA_NODESTORE_GETFROMREF(UA_Server *server, UA_NodePointer target) {
    return server->config.nodestore->
        getNodeFromPtr(server->config.nodestore,
                       target, UA_NODEATTRIBUTESMASK_ALL,
                       UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
}

#define UA_NODESTORE_GET_SELECTIVE(server, nodeid, attrMask, refs, refDirs) \
    server->config.nodestore->getNode(server->config.nodestore,             \
                                      nodeid, attrMask, refs, refDirs)

#define UA_NODESTORE_GET_EDIT_SELECTIVE(server, nodeid, attrMask, refs, refDirs) \
    server->config.nodestore->getEditNode(server->config.nodestore,              \
                                          nodeid, attrMask, refs, refDirs)

#define UA_NODESTORE_GETFROMREF_SELECTIVE(server, target, attrMask, refs, refDirs) \
    server->config.nodestore->getNodeFromPtr(server->config.nodestore,             \
                                             target, attrMask, refs, refDirs)

#define UA_NODESTORE_RELEASE(server, node)                              \
    server->config.nodestore->releaseNode(server->config.nodestore, node)

#define UA_NODESTORE_GETCOPY(server, nodeid, outnode)                      \
    server->config.nodestore->getNodeCopy(server->config.nodestore, nodeid, outnode)

#define UA_NODESTORE_INSERT(server, node, addedNodeId)                    \
    server->config.nodestore->insertNode(server->config.nodestore, node, addedNodeId)

#define UA_NODESTORE_REPLACE(server, node)                              \
    server->config.nodestore->replaceNode(server->config.nodestore, node)

#define UA_NODESTORE_REMOVE(server, nodeId)                             \
    server->config.nodestore->removeNode(server->config.nodestore, nodeId)

#define UA_NODESTORE_GETREFERENCETYPEID(server, index)                  \
    server->config.nodestore->getReferenceTypeId(server->config.nodestore, index)

/* Handling of Locales */

/* Returns a shallow copy */
UA_LocalizedText
UA_Session_getNodeDisplayName(const UA_Session *session,
                              const UA_NodeHead *head);

UA_LocalizedText
UA_Session_getNodeDescription(const UA_Session *session,
                              const UA_NodeHead *head);

_UA_END_DECLS


/**** amalgamated original file "/src/client/ua_client_internal.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 */


#define UA_INTERNAL


_UA_BEGIN_DECLS

/**************************/
/* Subscriptions Handling */
/**************************/

typedef struct UA_Client_NotificationsAckNumber {
    LIST_ENTRY(UA_Client_NotificationsAckNumber) listEntry;
    UA_SubscriptionAcknowledgement subAck;
} UA_Client_NotificationsAckNumber;

typedef struct UA_Client_MonitoredItem {
    ZIP_ENTRY(UA_Client_MonitoredItem) zipfields;
    UA_UInt32 monitoredItemId;
    UA_UInt32 clientHandle;
    void *context;
    UA_Client_DeleteMonitoredItemCallback deleteCallback;
    union {
        UA_Client_DataChangeNotificationCallback dataChangeCallback;
        UA_Client_EventNotificationCallback eventCallback;
    } handler;
    UA_Boolean isEventMonitoredItem; /* Otherwise a DataChange MoniitoredItem */

    UA_KeyValueMap eventFields; /* Cached names */
} UA_Client_MonitoredItem;

ZIP_HEAD(MonitorItemsTree, UA_Client_MonitoredItem);
typedef struct MonitorItemsTree MonitorItemsTree;

typedef struct UA_Client_Subscription {
    LIST_ENTRY(UA_Client_Subscription) listEntry;
    UA_UInt32 subscriptionId;
    void *context;
    UA_Double publishingInterval;
    UA_UInt32 maxKeepAliveCount;
    UA_Client_StatusChangeNotificationCallback statusChangeCallback;
    UA_Client_DeleteSubscriptionCallback deleteCallback;
    UA_UInt32 sequenceNumber;
    UA_DateTime lastActivity;
    MonitorItemsTree monitoredItems;
} UA_Client_Subscription;

void
__Client_Subscriptions_clear(UA_Client *client);

/* Exposed for fuzzing */
UA_StatusCode
__Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request);

void
__Client_Subscriptions_backgroundPublish(UA_Client *client);

void
__Client_Subscriptions_backgroundPublishInactivityCheck(UA_Client *client);

/**********/
/* Client */
/**********/

typedef struct AsyncServiceCall {
    LIST_ENTRY(AsyncServiceCall) pointers;
    UA_UInt32 requestId;     /* Unique id */
    UA_UInt32 requestHandle; /* Potentially non-unique if manually defined in
                              * the request header*/
    UA_ClientAsyncServiceCallback callback;
    const UA_DataType *responseType;
    void *userdata;
    UA_DateTime start;
    UA_UInt32 timeout;
    UA_Response *syncResponse; /* If non-null, then this is the synchronous
                                * response to be filled. Set back to null to
                                * indicate that the response was filled. */
} AsyncServiceCall;

typedef LIST_HEAD(UA_AsyncServiceList, AsyncServiceCall) UA_AsyncServiceList;

void
__Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode);

typedef struct CustomCallback {
    UA_UInt32 callbackId;

    UA_ClientAsyncServiceCallback userCallback;
    void *userData;

    void *clientData;
} CustomCallback;

struct UA_Client {
    UA_ClientConfig config;

    /* Callback ID to remove it from the EventLoop */
    UA_UInt64 houseKeepingCallbackId;

    /* Overall connection status */
    UA_StatusCode connectStatus;

    /* Old status to notify only changes */
    UA_SecureChannelState oldChannelState;
    UA_SessionState oldSessionState;
    UA_StatusCode oldConnectStatus;

    UA_Boolean findServersHandshake;   /* Ongoing FindServers */
    UA_Boolean endpointsHandshake;     /* Ongoing GetEndpoints */
    UA_Boolean namespacesHandshake;    /* Ongoing Namespaces read */
    UA_Boolean haveNamespaces;         /* Do we have the namespaces? */

    /* The discoveryUrl can be different from the EndpointUrl in the client
     * configuration. The EndpointUrl is used to connect initially, then the
     * DiscoveryUrl is selected via FindServers. This triggers a reconnect if
     * EndpointUrl != DiscoveryUrl. */
    UA_String discoveryUrl;

    /* Contains the Server description, etc. */
    UA_EndpointDescription endpoint;

    UA_RuleHandling allowAllCertificateUris;

    /* SecureChannel */
    UA_SecureChannel channel;
    UA_UInt32 requestId; /* Unique, internally defined for each request */
    UA_DateTime nextChannelRenewal;

    /* Reverse connect (listen) connections */
    UA_ConnectionManager *reverseConnectionCM;
    uintptr_t reverseConnectionIds[16];

    /* Session */
    UA_NodeId sessionId;
    UA_SessionState sessionState;
    UA_NodeId authenticationToken;
    UA_UInt32 requestHandle; /* Unique handles >100,000 are generated if the
                              * request header contains a zero-handle. */
    UA_ByteString serverSessionNonce;
    UA_ByteString clientSessionNonce;

    /* The SecurityPolicy corresponding to the UserTokenPolicy. Either for
     * encrypting the password (secret) or for signing with the private key of
     * the certificate in the UserIdentityToken. */
    UA_SecurityPolicy *utpSp;
    void *utpSpContext;

    /* For authentication with an ECC SecurityPolicy. This is needed to save the
     * server's ephemeral public key between the session creation (when the key
     * is received) and session activation, when the key is used. */
    UA_ByteString serverEphemeralPubKey;

    /* Connectivity check */
    UA_DateTime lastConnectivityCheck;
    UA_Boolean pendingConnectivityCheck;

    /* Async Service */
    UA_AsyncServiceList asyncServiceCalls;

    /* Subscriptions */
    LIST_HEAD(, UA_Client_NotificationsAckNumber) pendingNotificationsAcks;
    LIST_HEAD(, UA_Client_Subscription) subscriptions;
    UA_UInt32 monitoredItemHandles;
    UA_UInt16 currentlyOutStandingPublishRequests;

    /* Internal namespaces. The table maps the namespace Uri to its index. This
     * is used for the automatic namespace mapping in de/encoding. */
    UA_String *namespaces;
    size_t namespacesSize;

    /* Internal locking for thread-safety. Methods starting with UA_Client_ that
     * are marked with UA_THREADSAFE take the lock. The lock is released before
     * dropping into the EventLoop and before calling user-defined callbacks.
     * That way user-defined callbacks can themselves call thread-safe client
     * methods. */
#if UA_MULTITHREADING >= 100
    UA_Lock clientMutex;
#endif
};

/* In order to prevent deadlocks between the EventLoop mutex and the
 * client-mutex, we always take the EventLoop mutex first. */

void lockClient(UA_Client *client);
void unlockClient(UA_Client *client);

UA_StatusCode
__Client_AsyncService(UA_Client *client, const void *request,
                      const UA_DataType *requestType,
                      UA_ClientAsyncServiceCallback callback,
                      const UA_DataType *responseType,
                      void *userdata, UA_UInt32 *requestId);

void
__Client_Service(UA_Client *client, const void *request,
                 const UA_DataType *requestType, void *response,
                 const UA_DataType *responseType);

UA_StatusCode
__UA_Client_startup(UA_Client *client);

/* Connect with the client configuration. For the async connection, finish
 * connecting via UA_Client_run_iterate (or manually running a configured
 * external EventLoop). */
UA_StatusCode
__UA_Client_connect(UA_Client *client, UA_Boolean async, const char *endpointUrl);

void
__UA_Client_Service(UA_Client *client, const void *request,
                    const UA_DataType *requestType, void *response,
                    const UA_DataType *responseType);

UA_StatusCode
__Client_renewSecureChannel(UA_Client *client);

UA_StatusCode
processServiceResponse(UA_Client *client, UA_SecureChannel *channel,
                       UA_MessageType messageType, UA_UInt32 requestId,
                       UA_ByteString *message);

UA_StatusCode connectInternal(UA_Client *client, UA_Boolean async);
UA_StatusCode connectSecureChannel(UA_Client *client, const char *endpointUrl);
UA_Boolean isFullyConnected(UA_Client *client);
void connectSync(UA_Client *client);
void setConnectStatus(UA_Client *client, UA_StatusCode status);
void notifyClientState(UA_Client *client);
void processRHEMessage(UA_Client *client, const UA_ByteString *chunk);
void processERRResponse(UA_Client *client, const UA_ByteString *chunk);
void processACKResponse(UA_Client *client, const UA_ByteString *chunk);
void processOPNResponse(UA_Client *client, const UA_ByteString *message);
void closeSecureChannel(UA_Client *client);
void cleanupSession(UA_Client *client);

void
Client_warnEndpointsResult(UA_Client *client,
                           const UA_GetEndpointsResponse *response,
                           const UA_String *endpointUrl);

_UA_END_DECLS


/**** amalgamated original file "1_build/src_generated/open62541/namespace0_generated.h" ****/

/* WARNING: This is a generated file.
 * Any manual changes will be overwritten. */

#ifndef NAMESPACE0_GENERATED_H_
#define NAMESPACE0_GENERATED_H_





_UA_BEGIN_DECLS

extern UA_StatusCode namespace0_generated(UA_Server *server);

_UA_END_DECLS

#endif /* NAMESPACE0_GENERATED_H_ */

/**** amalgamated original file "/src/util/ua_eventfilter_parser.h" ****/

/* This Source Code Form is subjec&t to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2023-2024 (c) Fraunhofer IOSB (Author: Florian Düwel)
 */



_UA_BEGIN_DECLS

/* The following token identifiers are generated from ua_eventfilter_grammar.y.
 * They need to be udpated here whenever the grammar is changed. */
#define EF_TOK_OR                               1
#define EF_TOK_AND                              2
#define EF_TOK_NOT                              3
#define EF_TOK_BINARY_OP                        4
#define EF_TOK_BETWEEN                          5
#define EF_TOK_INLIST                           6
#define EF_TOK_UNARY_OP                         7
#define EF_TOK_SELECT                           8
#define EF_TOK_COMMA                            9
#define EF_TOK_WHERE                           10
#define EF_TOK_SAO                             11
#define EF_TOK_LITERAL                         12
#define EF_TOK_NAMEDOPERAND                    13
#define EF_TOK_LPAREN                          14
#define EF_TOK_RPAREN                          15
#define EF_TOK_LBRACKET                        16
#define EF_TOK_RBRACKET                        17
#define EF_TOK_FOR                             18
#define EF_TOK_COLONEQUAL                      19

typedef union {
    UA_FilterOperator filter;
    UA_String text;
    UA_SimpleAttributeOperand sao;
} Token;

struct Operand;
typedef struct Operand Operand;

typedef struct {
    UA_FilterOperator filter;
    size_t childrenSize;
    Operand **children;
    UA_Boolean required; /* Referenced in the operator hierarchy */
    size_t elementIndex; /* If non-null, then the Operator has been printed out
                          * already to the final EventFilter in the element
                          * array. */
} Operator;

typedef enum { OT_OPERATOR, OT_REF, OT_SAO, OT_LITERAL } OperandType;

struct Operand {
    char *ref; /* The operand has a name */
    OperandType type;
    union {
        Operator op;
        char *ref; /* Reference to another operand with a name */
        UA_SimpleAttributeOperand sao;
        UA_Variant literal;
    } operand;
    LIST_ENTRY(Operand) entries;
    TAILQ_ENTRY(Operand) select_entries;
    Operand *next; /* For the INLINST operator list */
};

typedef struct {
    const UA_Logger *logger;
    LIST_HEAD(, Operand) operands;
    size_t operandsSize;
    TAILQ_HEAD(, Operand) select_operands;
    Operand *top;
    UA_StatusCode error;
} EFParseContext;

void EFParseContext_clear(EFParseContext *ctx);

char * save_string(char *str);
Operand * create_operand(EFParseContext *ctx, OperandType ot);
Operand * create_operator(EFParseContext *ctx, UA_FilterOperator fo);
void append_operand(Operand *op, Operand *on);
void append_select(EFParseContext *ctx, Operand *on);
UA_StatusCode create_filter(EFParseContext *ctx, UA_EventFilter *filter);

/* Skip whitespace and comments */
UA_StatusCode
UA_EventFilter_skip(const UA_ByteString content, size_t *offset, EFParseContext *ctx);

/* The begin offset is set to the beginning of the token (after comments and
 * whitespace). If we we attempt to parse a token. */
int UA_EventFilter_lex(const UA_ByteString content, size_t *offset,
                       EFParseContext *ctx, Operand **token);

/* Translate from the offset to lines/columns of the input */
void
pos2lines(const UA_ByteString content, size_t pos,
          unsigned *outLine, unsigned *outCol);

_UA_END_DECLS


/**** amalgamated original file "/deps/cj5.h" ****/

// MIT License
//
// Copyright (c) 2020 Sepehr Taghdisian
// Copyright (c) 2022, 2024 Julius Pfrommer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Very minimal single header JSON5 parser in C99, dervied from jsmn This is the
// modified version of jsmn library Thus main parts of the code is taken from
// jsmn project (https://github.com/zserge/jsmn).
//
// Compliance with JSON5:
//  [x] Object keys may be an ECMAScript 5.1 IdentifierName.
//  [x] Objects may have a single trailing comma.
//  [x] Strings may be single quoted.
//  [x] Strings may span multiple lines by escaping new line characters.
//  [x] Strings may include character escapes.
//  [x] Numbers may be hexadecimal.
//  [x] Numbers may have a leading or trailing decimal point.
//  [x] Numbers may be IEEE 754 positive infinity, negative infinity, and NaN.
//  [x] Numbers may begin with an explicit plus sign.
//  [x] Single and multi-line comments are allowed.
//  [x] Additional white space characters are allowed.
//
// Extensions to JSON5 (more permissive):
//  [x] Root objects can be an array or a primitive value
//  [x] The root object may omit the surrounding brackets
//  [x] Hash ('#') comments out until the end of the line.
//  [x] Strings may include unescaped utf8 bytes
//  [x] Booleans and null are case-insensitive
//  [x] Optionally: Stop early when the first encountered JSON element (object,
//      array, value) has been successfully parsed. Do not return an error when
//      the input string was not processed to its full length. This allows the
//      detection of JSON sub-strings as part of an input "lexer".
//
// Usage:
//  The main function to parse json is `cj5_parse`. Like in jsmn, you provide
//  all tokens to be filled as an array and provide the maximum count The result
//  will be return in `cj5_result` struct, and `num_tokens` will represent the
//  actual token count that is parsed. In case of errors, cj_result.error will
//  be set to an error code Here's a quick example of the usage.
//  
//  #include "cj5.h"
//
//  cj5_token tokens[32];
//  cj5_result r = cj5_parse(g_json, (int)strlen(g_json), tokens, 32, NULL);
//  if(r.error != CJ5_ERROR_NONE) {
//      if(r.error == CJ5_ERROR_OVERFLOW) {
//          // you can use r.num_tokens to determine the actual token count and reparse
//          printf("Error: line: %d, col: %d\n", r.error_line, r.error_code);    
//      }
//  }

#ifndef __CJ5_H_
#define __CJ5_H_

#ifdef __cplusplus
# define CJ5_API extern "C"
#else
# define CJ5_API
#endif

#include <stdint.h>
#include <stdbool.h>

typedef enum cj5_token_type {
    CJ5_TOKEN_OBJECT = 0,
    CJ5_TOKEN_ARRAY,
    CJ5_TOKEN_NUMBER,
    CJ5_TOKEN_STRING,
    CJ5_TOKEN_BOOL,
    CJ5_TOKEN_NULL
} cj5_token_type;

typedef enum cj5_error_code {
    CJ5_ERROR_NONE = 0,
    CJ5_ERROR_INVALID,       // Invalid character/syntax
    CJ5_ERROR_INCOMPLETE,    // Incomplete JSON string
    CJ5_ERROR_OVERFLOW,      // Token buffer overflow (see cj5_result.num_tokens)
    CJ5_ERROR_NOTFOUND
} cj5_error_code;

typedef struct cj5_token {
    cj5_token_type type;
    unsigned int start;     // Start position in the json5 string
    unsigned int end;       // Position of the last character (included)
    unsigned int size;      // For objects and arrays the number of direct
                            // children. Note that this is *not* the number of
                            // overall (recursively nested) child tokens. For
                            // other tokens the length of token in the json
                            // encoding.
    unsigned int parent_id; // The root object is at position zero. It is an
                            // object that has itself as parent.
} cj5_token;

typedef struct cj5_result {
    cj5_error_code error;
    unsigned int error_pos;
    unsigned int num_tokens;
    const cj5_token* tokens;
    const char* json5;
} cj5_result;

typedef struct cj5_options {
    bool stop_early; /* Return when the first element was parsed. Otherwise an
                      * error is returned if the input was not fully
                      * processed. (default: false) */
} cj5_options;

/* Options can be NULL */
CJ5_API cj5_result
cj5_parse(const char *json5, unsigned int len,
          cj5_token *tokens, unsigned int max_tokens,
          cj5_options *options);

CJ5_API cj5_error_code
cj5_get_bool(const cj5_result *r, unsigned int tok_index, bool *out);

CJ5_API cj5_error_code
cj5_get_float(const cj5_result *r, unsigned int tok_index, double *out);

CJ5_API cj5_error_code
cj5_get_int(const cj5_result *r, unsigned int tok_index, int64_t *out);

CJ5_API cj5_error_code
cj5_get_uint(const cj5_result *r, unsigned int tok_index, uint64_t *out);

// Replaces escape characters, utf8 codepoints, etc.
// The buffer shall have a length of at least token->size + 1.
// Upon success, the length is written to buflen.
// The output string is terminated with \0.
CJ5_API cj5_error_code
cj5_get_str(const cj5_result *r, unsigned int tok_index,
            char *buf, unsigned int *buflen);

// Skips the (nested) structure that starts at the current index. The index is
// updated accordingly. Afterwards it points to the beginning of the following
// structure.
//
// Attention! The index can point to the first element after the token array if
// the root object is skipped.
//
// Cannot fail as long as the token array is the result of cj5_parse.
CJ5_API void
cj5_skip(const cj5_result *r, unsigned int *tok_index);

// Lookup of a key within an object (linear search).
// The current token (index) must point to an object.
// The error code CJ5_ERROR_NOTFOUND is returned if the key is not present.
// Otherwise the index is updated to point to the value associated with the key.
CJ5_API cj5_error_code
cj5_find(const cj5_result *r, unsigned int *tok_index, const char *key);

#endif /* __CJ5_H_ */

/**** amalgamated original file "/src/ua_types_encoding_json.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Lukas Meling)
 */





_UA_BEGIN_DECLS

#define UA_JSON_MAXTOKENCOUNT 256
#define UA_JSON_ENCODING_MAX_RECURSION 100

typedef struct {
    uint8_t *pos;
    const uint8_t *end;

    uint16_t depth; /* How often did we en-/decoding recurse? */
    UA_Boolean commaNeeded[UA_JSON_ENCODING_MAX_RECURSION];
    UA_Boolean useReversible;
    UA_Boolean calcOnly; /* Only compute the length of the decoding */

    UA_NamespaceMapping *namespaceMapping;

    size_t serverUrisSize;
    const UA_String *serverUris;

    UA_Boolean prettyPrint;
    UA_Boolean unquotedKeys;
    UA_Boolean stringNodeIds;
} CtxJson;

UA_StatusCode writeJsonObjStart(CtxJson *ctx);
UA_StatusCode writeJsonObjElm(CtxJson *ctx, const char *key,
                              const void *value, const UA_DataType *type);
UA_StatusCode writeJsonObjEnd(CtxJson *ctx);

UA_StatusCode writeJsonArrStart(CtxJson *ctx);
UA_StatusCode writeJsonArrElm(CtxJson *ctx, const void *value,
                              const UA_DataType *type);
UA_StatusCode writeJsonArrEnd(CtxJson *ctx, const UA_DataType *type);

UA_StatusCode writeJsonKey(CtxJson *ctx, const char* key);

/* Adds a comma if needed. Distinct elements go on a new line if pretty-printing
 * is enabled. */
UA_StatusCode writeJsonBeforeElement(CtxJson *ctx, UA_Boolean distinct);

typedef struct {
    const char *json5;
    cj5_token *tokens;
    size_t tokensSize;
    size_t index;
    UA_Byte depth;

    UA_NamespaceMapping *namespaceMapping;

    size_t serverUrisSize;
    const UA_String *serverUris;

    const UA_DataTypeArray *customTypes;
} ParseCtx;

typedef UA_StatusCode
(*encodeJsonSignature)(CtxJson *ctx, const void *src, const UA_DataType *type);

typedef UA_StatusCode
(*decodeJsonSignature)(ParseCtx *ctx, void *dst, const UA_DataType *type);

/* Map for decoding a Json Object. An array of this is passed to the
 * decodeFields function. If the key "fieldName" is found in the json object
 * (mark as found and) decode the value with the "function" and write result
 * into "fieldPointer" (destination). */
typedef struct {
    const char *fieldName;
    void *fieldPointer;
    decodeJsonSignature function;
    UA_Boolean found;
    const UA_DataType *type; /* Must be set for values that can be "null". If
                              * the function is not set, decode via the
                              * type->typeKind. */
} DecodeEntry;

UA_StatusCode decodeFields(ParseCtx *ctx, DecodeEntry *entries, size_t entryCount);

/* Expose the jump tables and some methods for PubSub JSON decoding */
extern const encodeJsonSignature encodeJsonJumpTable[UA_DATATYPEKINDS];
extern const decodeJsonSignature decodeJsonJumpTable[UA_DATATYPEKINDS];

UA_StatusCode lookAheadForKey(ParseCtx *ctx, const char *search, size_t *resultIndex);
UA_StatusCode tokenize(ParseCtx *ctx, const UA_ByteString *src, size_t tokensSize,
                       size_t *decodedLength);

static UA_INLINE
cj5_token_type currentTokenType(const ParseCtx *ctx) {
    return ctx->tokens[ctx->index].type;
}

static UA_INLINE
size_t getTokenLength(const cj5_token *t) {
    return (size_t)(1u + t->end - t->start);
}

_UA_END_DECLS


/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Tino Bischoff)
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2025 Fraunhofer IOSB (Author: Julius Pfrommer)
 */



#ifdef UA_ENABLE_JSON_ENCODING
#endif

#ifdef UA_ENABLE_PUBSUB

_UA_BEGIN_DECLS

typedef struct {
    Ctx ctx;
    UA_NetworkMessage_EncodingOptions eo;
    UA_PubSubOffsetTable *ot;
} PubSubEncodeCtx;

typedef struct {
    Ctx ctx;
    UA_NetworkMessage_EncodingOptions eo;
} PubSubDecodeCtx;

#ifdef UA_ENABLE_JSON_ENCODING
typedef struct {
    CtxJson ctx;
    UA_NetworkMessage_EncodingOptions eo;
} PubSubEncodeJsonCtx;

typedef struct {
    ParseCtx ctx;
    UA_NetworkMessage_EncodingOptions eo;
} PubSubDecodeJsonCtx;
#endif

const UA_FieldMetaData *
getFieldMetaData(const UA_DataSetMessage_EncodingMetaData *emd,
                 size_t index);

const UA_DataSetMessage_EncodingMetaData *
findEncodingMetaData(const UA_NetworkMessage_EncodingOptions *eo,
                     UA_UInt16 dsWriterId);

/******************/
/* DataSetMessage */
/******************/

UA_StatusCode
UA_DataSetMessageHeader_encodeBinary(PubSubEncodeCtx *ctx,
                                     const UA_DataSetMessageHeader *src);

UA_StatusCode
UA_DataSetMessageHeader_decodeBinary(PubSubDecodeCtx *ctx,
                                     UA_DataSetMessageHeader *dst);

UA_StatusCode
UA_DataSetMessage_encodeBinary(PubSubEncodeCtx *ctx,
                               const UA_DataSetMessage_EncodingMetaData *emd,
                               const UA_DataSetMessage *src);

UA_StatusCode
UA_DataSetMessage_decodeBinary(PubSubDecodeCtx *ctx,
                               const UA_DataSetMessage_EncodingMetaData *em,
                               UA_DataSetMessage *dsm,
                               size_t dsmSize);

size_t
UA_DataSetMessage_calcSizeBinary(PubSubEncodeCtx *ctx,
                                 const UA_DataSetMessage_EncodingMetaData *em,
                                 UA_DataSetMessage *src,
                                 size_t currentOffset);

/******************/
/* NetworkMessage */
/******************/

size_t
UA_NetworkMessage_calcSizeBinaryInternal(PubSubEncodeCtx *ctx,
                                         const UA_NetworkMessage *src);

UA_StatusCode
UA_NetworkMessage_encodeHeaders(PubSubEncodeCtx *ctx,
                                const UA_NetworkMessage *src);

UA_StatusCode
UA_NetworkMessage_encodePayload(PubSubEncodeCtx *ctx,
                                const UA_NetworkMessage *src);

UA_StatusCode
UA_NetworkMessage_encodeFooters(PubSubEncodeCtx *ctx,
                                const UA_NetworkMessage *src);

UA_StatusCode
UA_NetworkMessage_decodeHeaders(PubSubDecodeCtx *ctx,
                                UA_NetworkMessage *dst);

UA_StatusCode
UA_NetworkMessage_decodePayload(PubSubDecodeCtx *ctx,
                                UA_NetworkMessage *dst);

UA_StatusCode
UA_NetworkMessage_decodeFooters(PubSubDecodeCtx *ctx,
                                UA_NetworkMessage *dst);

void
UA_NetworkMessage_makeSyntheticPayloadHeader(const UA_NetworkMessage_EncodingOptions *eo,
                                             UA_NetworkMessage *dst);

UA_StatusCode
UA_NetworkMessage_encodeBinaryWithEncryptStart(PubSubEncodeCtx *ctx,
                                               const UA_NetworkMessage *src,
                                               UA_Byte **dataToEncryptStart);

UA_StatusCode
UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm,
                              UA_MessageSecurityMode securityMode,
                              UA_PubSubSecurityPolicy *policy,
                              void *policyContext,
                              UA_Byte *messageStart,
                              UA_Byte *encryptStart,
                              UA_Byte *sigStart);

#ifdef UA_ENABLE_JSON_ENCODING
UA_StatusCode
UA_NetworkMessage_encodeJsonInternal(PubSubEncodeJsonCtx *ctx,
                                     const UA_NetworkMessage *src);
#endif

_UA_END_DECLS

#endif /* UA_ENABLE_PUBSUB */


/**** amalgamated original file "/src/pubsub/ua_pubsub_internal.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020, 2022 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#define UA_INTERNAL


/**
 * PubSub State Machine
 * --------------------
 * 
 * The following table described the behaviour of components expected during
 * state changes and also the integration which is expected between the
 * components.
 *
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |**Component**   |       |**Disabled**        |**Paused**      |**Pre-Operational** |**Operational** |**Error**       |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |PubSubConnection|Trigger|Manual disable      |Connection      |Manual enable ||    |Pre-Operational |Unrecoverable   |
 * |                |       |                    |enabled but the |Recoverable abort of|&& Connected    |abort of the    |
 * |                |       |                    |server is not   |EventLoop connection|EventLoop       |EventLoop       |
 * |                |       |                    |running.        |                    |connection      |connection ||   |
 * |                |       |                    |                |                    |                |Internal Error  |
 * |                +-------+--------------------+----------------+--------------------+----------------+----------------+
 * |                |Action |The underlying      |                |Start the async     |                |Same as the     |
 * |                |       |connection is closed|                |opening of the      |                |Disabled case   |
 * |                |       |(async). Immediately|                |underlying EventLoop|                |                |
 * |                |       |set the EventLoop   |                |connection.         |                |                |
 * |                |       |connection context  |                |Automatically switch|                |                |
 * |                |       |pointer to NULL. So |                |to operational when |                |                |
 * |                |       |that the            |                |the EventLoop       |                |                |
 * |                |       |PubSubConnection can|                |connection is fully |                |                |
 * |                |       |be freed without    |                |open. This can only |                |                |
 * |                |       |waiting for the     |                |be signaled by the  |                |                |
 * |                |       |EventLoop connection|                |underlying EventLoop|                |                |
 * |                |       |to finish closing.  |                |connection in the   |                |                |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |WriterGroup     |Trigger|Manual disable      |WG is enabled &&|WG is enabled &&    |WG is enabled &&|Internal error  |
 * |                |       |                    |PubSubConnection|PubSubConnection    |PubSubConnection|                |
 * |                |       |                    |not enabled     |Pre-Operational     |Operational     |                |
 * |                +-------+--------------------+----------------+--------------------+----------------+----------------+
 * |                |Action |Publish callback    |Publish callback|Publish callback    |Publish callback|Publish callback|
 * |                |       |deregistered        |deregistered    |deregistered        |registered      |deregistered    |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |DataSetWriter   |Trigger|Manual disable      |DSW enabled &&  |DSW enabled && WG   |DSW enabled &&  |Internal error  |
 * |                |       |                    |WG is not       |Pre-Operational     |WG is           |                |
 * |                |       |                    |enabled         |                    |Operational     |                |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |ReaderGroup     |Trigger|Manual disable      |RG enabled &&   |RG enabled &&       |RG enabled &&   |Internal error  |
 * |                |       |                    |PubSubConnection|(PubSubConnection   |PubSubConnection|                |
 * |                |       |                    |not enabled     |Pre-Operational ||  |Operational &&  |                |
 * |                |       |                    |                |RG-connection not   |RG-connection   |                |
 * |                |       |                    |                |fully established)  |established     |                |
 * |                +-------+--------------------+----------------+--------------------+----------------+----------------+
 * |                |Action |RG connection       |RG connection   |RG connection       |RG connection   |RG connection   |
 * |                |       |disconnected        |disconnected    |connected           |connected       |disconnected    |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |DataSetReader   |Trigger|Manual disable      |DSR enabled &&  |DSR enabled && RG   |DSR enabled &&  |Internal error  |
 * |                |       |                    |RG not enabled  |Pre-Operational     |RG Operational  |                |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 */

_UA_BEGIN_DECLS

#ifdef UA_ENABLE_PUBSUB

/* Max number of underlying sockets for sending and receiving for every
 * PubSubConnection. Note that a PubSubConnection may have WriterGroups with
 * dedicated sockets. Because for UDP unicast only the WriterGroup has the
 * target host information. */
#define UA_PUBSUB_MAXCHANNELS 8

#define UA_PUBSUB_PROFILES_SIZE 4

struct UA_WriterGroup;
typedef struct UA_WriterGroup UA_WriterGroup;

struct UA_ReaderGroup;
typedef struct UA_ReaderGroup UA_ReaderGroup;

struct UA_SecurityGroup;
typedef struct UA_SecurityGroup UA_SecurityGroup;

struct UA_DataSetReader;
typedef struct UA_DataSetReader UA_DataSetReader;

struct UA_PubSubManager;
typedef struct UA_PubSubManager UA_PubSubManager;

struct UA_PubSubKeyStorage;
typedef struct UA_PubSubKeyStorage UA_PubSubKeyStorage;

/* Get the matching ConnectionManager from the EventLoop */
UA_ConnectionManager *
getCM(UA_EventLoop *el, UA_String protocol);

const char *
UA_PubSubState_name(UA_PubSubState state);

/* A component is considered enabled if it is not in the DISABLED or ERROR
 * state. All other states (also PAUSED) can lead to automatic recovery into
 * OPERATIONAL. */
static UA_INLINE UA_Boolean
UA_PubSubState_isEnabled(UA_PubSubState state) {
    return (state != UA_PUBSUBSTATE_DISABLED &&
            state != UA_PUBSUBSTATE_ERROR);
}

/* All PubSubComponents share the same header structure */

typedef struct {
    UA_NodeId identifier;
    UA_PubSubComponentType componentType;
    UA_PubSubState state;
    UA_String logIdString; /* Precomputed logging prefix */
    UA_Boolean transientState; /* We are in the middle of a state update */
} UA_PubSubComponentHead;

#define UA_LOG_PUBSUB_INTERNAL(LOGGER, LEVEL, COMPONENT, MSG, ...)      \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%S" MSG "%.0s",  \
                       (COMPONENT)->head.logIdString, __VA_ARGS__);     \
    }

#define UA_LOG_TRACE_PUBSUB(LOGGER, COMPONENT, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, TRACE, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_PUBSUB(LOGGER, COMPONENT, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, DEBUG, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_INFO_PUBSUB(LOGGER, COMPONENT, ...)                           \
    UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, INFO, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_WARNING_PUBSUB(LOGGER, COMPONENT, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, WARNING, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_ERROR_PUBSUB(LOGGER, COMPONENT, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, ERROR, COMPONENT, __VA_ARGS__, ""))
#define UA_LOG_FATAL_PUBSUB(LOGGER, COMPONENT, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_PUBSUB_INTERNAL(LOGGER, FATAL, COMPONENT, __VA_ARGS__, ""))

void
UA_PubSubComponentHead_clear(UA_PubSubComponentHead *psch);

/**********************************************/
/*            PublishedDataSet                */
/**********************************************/

typedef struct UA_PublishedDataSet {
    UA_PubSubComponentHead head;
    TAILQ_ENTRY(UA_PublishedDataSet) listEntry;
    TAILQ_HEAD(, UA_DataSetField) fields;
    UA_PublishedDataSetConfig config;
    UA_DataSetMetaDataType dataSetMetaData;
    UA_UInt16 fieldSize;
    UA_UInt16 promotedFieldsCount;

    /* The counter is required because the PDS has not state.
     * Check if it is actively used when changes are introduced. */
    UA_UInt16 configurationFreezeCounter;
} UA_PublishedDataSet;

UA_StatusCode
UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src,
                               UA_PublishedDataSetConfig *dst);

UA_PublishedDataSet *
UA_PublishedDataSet_find(UA_PubSubManager *psm, const UA_NodeId id);

UA_PublishedDataSet *
UA_PublishedDataSet_findByName(UA_PubSubManager *psm, const UA_String name);

UA_AddPublishedDataSetResult
UA_PublishedDataSet_create(UA_PubSubManager *psm,
                           const UA_PublishedDataSetConfig *publishedDataSetConfig,
                           UA_NodeId *pdsIdentifier);

UA_StatusCode
UA_PublishedDataSet_remove(UA_PubSubManager *psm, UA_PublishedDataSet *pds);

/*********************/
/* SubscribedDataSet */
/*********************/

typedef struct UA_SubscribedDataSet {
    UA_PubSubComponentHead head;
    TAILQ_ENTRY(UA_SubscribedDataSet) listEntry;
    UA_SubscribedDataSetConfig config;
    UA_DataSetReader *connectedReader;
} UA_SubscribedDataSet;

UA_StatusCode
UA_SubscribedDataSetConfig_copy(const UA_SubscribedDataSetConfig *src,
                                UA_SubscribedDataSetConfig *dst);

UA_SubscribedDataSet *
UA_SubscribedDataSet_find(UA_PubSubManager *psm, const UA_NodeId id);

UA_SubscribedDataSet *
UA_SubscribedDataSet_findByName(UA_PubSubManager *psm, const UA_String name);

void
UA_SubscribedDataSet_remove(UA_PubSubManager *psm, UA_SubscribedDataSet *sds);

/**********************************************/
/*               Connection                   */
/**********************************************/

typedef struct UA_PubSubConnection {
    UA_PubSubComponentHead head;
    TAILQ_ENTRY(UA_PubSubConnection) listEntry;

    /* The send/recv connections are only opened if the state is operational */
    UA_PubSubConnectionConfig config;
    UA_Boolean json; /* Extracted from the TransportProfileUrl */

    /* Channels belonging to the PubSubConnection. Send channels belong to
     * WriterGroups, recv channels belong to ReaderGroups. We only open channels 
     * if there is at least one WriterGroup/ReaderGroup respectively.
     *
     * Some channels belong exclusively to just one WriterGroup/ReaderGroup that
     * defines additional connection properties. For example an MQTT topic name
     * or QoS parameters. In that case a dedicated NetworkCallback is used that
     * takes this ReaderGroup/WriterGroup directly as context. */
    UA_ConnectionManager *cm;
    uintptr_t recvChannels[UA_PUBSUB_MAXCHANNELS];
    size_t recvChannelsSize;
    uintptr_t sendChannel;

    size_t writerGroupsSize;
    LIST_HEAD(, UA_WriterGroup) writerGroups;

    size_t readerGroupsSize;
    LIST_HEAD(, UA_ReaderGroup) readerGroups;

    UA_DateTime silenceErrorUntil; /* Avoid generating too many logs */

    UA_Boolean deleteFlag; /* To be deleted - in addition to the PubSubState */
    UA_DelayedCallback dc; /* For delayed freeing */
} UA_PubSubConnection;

UA_PubSubConnection *
UA_PubSubConnection_find(UA_PubSubManager *psm, const UA_NodeId id);

UA_StatusCode
UA_PubSubConnection_create(UA_PubSubManager *psm,
                           const UA_PubSubConnectionConfig *connectionConfig,
                           UA_NodeId *connectionIdentifier);

UA_StatusCode
UA_PubSubConnection_delete(UA_PubSubManager *psm, UA_PubSubConnection *c);

UA_StatusCode
UA_PubSubConnection_setPubSubState(UA_PubSubManager *psm, UA_PubSubConnection *c,
                                   UA_PubSubState targetState);

/**********************************************/
/*              DataSetWriter                 */
/**********************************************/

typedef struct UA_DataSetWriterSample {
    UA_Boolean valueChanged;
    UA_DataValue value;
} UA_DataSetWriterSample;

typedef struct UA_DataSetWriter {
    UA_PubSubComponentHead head;
    LIST_ENTRY(UA_DataSetWriter) listEntry;

    UA_DataSetWriterConfig config;
    UA_WriterGroup *linkedWriterGroup;
    UA_PublishedDataSet *connectedDataSet;
    UA_ConfigurationVersionDataType connectedDataSetVersion;

    /* Deltaframes */
    UA_UInt16 deltaFrameCounter; /* count of sent deltaFrames */
    size_t lastSamplesCount;
    UA_DataSetWriterSample *lastSamples;

    UA_UInt16 actualDataSetMessageSequenceCount;
    UA_Boolean configurationFrozen;
    UA_UInt64 pubSubStateTimerId;
} UA_DataSetWriter;

UA_StatusCode
UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src,
                            UA_DataSetWriterConfig *dst);

UA_DataSetWriter *
UA_DataSetWriter_find(UA_PubSubManager *psm, const UA_NodeId id);

UA_StatusCode
UA_DataSetWriter_setPubSubState(UA_PubSubManager *psm, UA_DataSetWriter *dsw,
                                UA_PubSubState targetState);

UA_StatusCode
UA_DataSetWriter_generateDataSetMessage(UA_PubSubManager *psm,
                                        UA_DataSetWriter *dsw,
                                        UA_DataSetMessage *dsm);

UA_StatusCode
UA_DataSetWriter_create(UA_PubSubManager *psm,
                        const UA_NodeId writerGroup, const UA_NodeId dataSet,
                        const UA_DataSetWriterConfig *dataSetWriterConfig,
                        UA_NodeId *writerIdentifier);

UA_StatusCode
UA_DataSetWriter_remove(UA_PubSubManager *psm, UA_DataSetWriter *dsw);

/**********************************************/
/*               WriterGroup                  */
/**********************************************/

struct UA_WriterGroup {
    UA_PubSubComponentHead head;
    LIST_ENTRY(UA_WriterGroup) listEntry;

    UA_WriterGroupConfig config;

    LIST_HEAD(, UA_DataSetWriter) writers;
    UA_UInt32 writersCount;

    UA_UInt64 publishCallbackId; /* registered if != 0 */
    UA_UInt16 sequenceNumber; /* Increased after every sent message */
    UA_DateTime lastPublishTimeStamp;

    /* The ConnectionManager pointer is stored in the Connection. The channels
     * are either stored here or in the Connection, but never both. */
    UA_PubSubConnection *linkedConnection;
    uintptr_t sendChannel;
    UA_Boolean deleteFlag;

    UA_UInt32 securityTokenId;
    UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */
    void *securityPolicyContext;
#ifdef UA_ENABLE_PUBSUB_SKS
    UA_PubSubKeyStorage *keyStorage; /* non-owning pointer to keyStorage*/
#endif
};

UA_StatusCode
UA_WriterGroup_create(UA_PubSubManager *psm, const UA_NodeId connection,
                      const UA_WriterGroupConfig *writerGroupConfig,
                      UA_NodeId *writerGroupIdentifier);

UA_StatusCode
UA_WriterGroup_remove(UA_PubSubManager *psm, UA_WriterGroup *wg);

/* Exposed so we can change the publish interval without having to stop */
UA_StatusCode
UA_WriterGroup_addPublishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg);

void
UA_WriterGroup_removePublishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg);

UA_StatusCode
UA_WriterGroup_setEncryptionKeys(UA_PubSubManager *psm, UA_WriterGroup *wg,
                                 UA_UInt32 securityTokenId,
                                 const UA_ByteString signingKey,
                                 const UA_ByteString encryptingKey,
                                 const UA_ByteString keyNonce);

UA_StatusCode
UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src,
                          UA_WriterGroupConfig *dst);

UA_WriterGroup *
UA_WriterGroup_find(UA_PubSubManager *psm, const UA_NodeId id);

UA_StatusCode
UA_WriterGroup_setPubSubState(UA_PubSubManager *psm, UA_WriterGroup *wg,
                              UA_PubSubState targetState);

void
UA_WriterGroup_publishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg);

/**********************************************/
/*               DataSetField                 */
/**********************************************/

typedef struct UA_DataSetField {
    UA_DataSetFieldConfig config;
    TAILQ_ENTRY(UA_DataSetField) listEntry;
    UA_NodeId identifier;
    UA_NodeId publishedDataSet;     /* parent pds */
    UA_FieldMetaData fieldMetaData; /* contains the dataSetFieldId */
    UA_UInt64 sampleCallbackId;
    UA_Boolean sampleCallbackIsRegistered;
} UA_DataSetField;

UA_StatusCode
UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src,
                           UA_DataSetFieldConfig *dst);

UA_DataSetField *
UA_DataSetField_find(UA_PubSubManager *psm, const UA_NodeId id);

UA_DataSetFieldResult
UA_DataSetField_remove(UA_PubSubManager *psm, UA_DataSetField *currentField);

UA_DataSetFieldResult
UA_DataSetField_create(UA_PubSubManager *psm, const UA_NodeId publishedDataSet,
                       const UA_DataSetFieldConfig *fieldConfig,
                       UA_NodeId *fieldIdentifier);

void
UA_PubSubDataSetField_sampleValue(UA_PubSubManager *psm,
                                  UA_DataSetField *field,
                                  UA_DataValue *value);

/**********************************************/
/*               DataSetReader                */
/**********************************************/

struct UA_DataSetReader {
    UA_PubSubComponentHead head;
    LIST_ENTRY(UA_DataSetReader) listEntry;

    UA_DataSetReaderConfig config;
    UA_ReaderGroup *linkedReaderGroup;

    /* MessageReceiveTimeout handling */
    UA_UInt64 msgRcvTimeoutTimerId;
};

UA_DataSetReader *
UA_DataSetReader_find(UA_PubSubManager *psm, const UA_NodeId id);

/* Process Network Message using DataSetReader */
void
UA_DataSetReader_process(UA_PubSubManager *psm,
                         UA_DataSetReader *dataSetReader,
                         UA_DataSetMessage *dataSetMsg);

UA_StatusCode
UA_DataSetReader_generateDataSetMessage(UA_Server *server,
                                        UA_DataSetMessage *dsm,
                                        UA_DataSetReader *dsr);

UA_StatusCode
UA_DataSetReader_checkIdentifier(UA_PubSubManager *psm, UA_DataSetReader *dsr,
                                 UA_NetworkMessage *msg);

UA_StatusCode
UA_DataSetReader_create(UA_PubSubManager *psm, UA_NodeId readerGroupIdentifier,
                        const UA_DataSetReaderConfig *dataSetReaderConfig,
                        UA_NodeId *readerIdentifier);

UA_StatusCode
UA_DataSetReader_remove(UA_PubSubManager *psm, UA_DataSetReader *dsr);

UA_StatusCode
DataSetReader_createTargetVariables(UA_PubSubManager *psm, UA_DataSetReader *dsr,
                                    size_t targetsSize, const UA_FieldTargetDataType *targets);

/* Returns an error reason if the target state is `Error` */
UA_StatusCode
UA_DataSetReader_setPubSubState(UA_PubSubManager *psm, UA_DataSetReader *dsr,
                                UA_PubSubState targetState, UA_StatusCode errorReason);

/**********************************************/
/*                ReaderGroup                 */
/**********************************************/

struct UA_ReaderGroup {
    UA_PubSubComponentHead head;
    LIST_ENTRY(UA_ReaderGroup) listEntry;

    UA_ReaderGroupConfig config;

    LIST_HEAD(, UA_DataSetReader) readers;
    UA_UInt32 readersCount;

    UA_Boolean hasReceived; /* Received a message since the last _connect */

    /* The ConnectionManager pointer is stored in the Connection. The channels 
     * are either stored here or in the Connection, but never both. */
    UA_PubSubConnection *linkedConnection;
    uintptr_t recvChannels[UA_PUBSUB_MAXCHANNELS];
    size_t recvChannelsSize;
    UA_Boolean deleteFlag;

    UA_UInt32 securityTokenId;
    UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */
    void *securityPolicyContext;
#ifdef UA_ENABLE_PUBSUB_SKS
    UA_PubSubKeyStorage *keyStorage;
#endif
};

UA_StatusCode
UA_ReaderGroup_create(UA_PubSubManager *psm, UA_NodeId connectionId,
                      const UA_ReaderGroupConfig *rgc,
                      UA_NodeId *readerGroupId);

UA_StatusCode
UA_ReaderGroup_remove(UA_PubSubManager *psm, UA_ReaderGroup *rg);

UA_StatusCode
UA_ReaderGroup_connect(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                       UA_Boolean validate);

UA_Boolean
UA_ReaderGroup_canConnect(UA_ReaderGroup *rg);

void
UA_ReaderGroup_disconnect(UA_ReaderGroup *rg);

UA_StatusCode
UA_ReaderGroup_setEncryptionKeys(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                                 UA_UInt32 securityTokenId,
                                 const UA_ByteString signingKey,
                                 const UA_ByteString encryptingKey,
                                 const UA_ByteString keyNonce);

UA_StatusCode
UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src,
                          UA_ReaderGroupConfig *dst);

UA_ReaderGroup *
UA_ReaderGroup_find(UA_PubSubManager *psm, const UA_NodeId id);

UA_StatusCode
UA_ReaderGroup_setPubSubState(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                              UA_PubSubState targetState);

UA_Boolean
UA_ReaderGroup_process(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                       UA_NetworkMessage *nm);

/* The buffer is the entire message. The ctx->pos points after the decoded
 * header. The ctx->end is modified to remove padding, etc. */
UA_StatusCode
verifyAndDecryptNetworkMessage(const UA_Logger *logger, UA_ByteString buffer,
                               Ctx *ctx, UA_NetworkMessage *nm,
                               UA_ReaderGroup *rg);

UA_StatusCode
UA_ReaderGroup_decodeNetworkMessage(UA_PubSubManager *psm,
                                    UA_ReaderGroup *rg,
                                    UA_ByteString buffer,
                                    UA_NetworkMessage *nm);

#ifdef UA_ENABLE_JSON_ENCODING
UA_StatusCode
UA_ReaderGroup_decodeNetworkMessageJSON(UA_PubSubManager *psm,
                                        UA_ReaderGroup *rg,
                                        UA_ByteString buffer,
                                        UA_NetworkMessage *nm);
#endif

#ifdef UA_ENABLE_PUBSUB_SKS

/*********************************************************/
/*                    SecurityGroup                      */
/*********************************************************/

struct UA_SecurityGroup {
    UA_String securityGroupId;
    UA_SecurityGroupConfig config;
    UA_PubSubKeyStorage *keyStorage;
    UA_NodeId securityGroupNodeId;
    UA_UInt64 callbackId;
    UA_DateTime baseTime;
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    UA_NodeId securityGroupFolderId;
#endif
    TAILQ_ENTRY(UA_SecurityGroup) listEntry;
};

UA_StatusCode
UA_SecurityGroupConfig_copy(const UA_SecurityGroupConfig *src,
                            UA_SecurityGroupConfig *dst);

UA_SecurityGroup *
UA_SecurityGroup_findByName(UA_PubSubManager *psm, const UA_String name);

UA_SecurityGroup *
UA_SecurityGroup_find(UA_PubSubManager *psm, const UA_NodeId id);

void
UA_SecurityGroup_remove(UA_PubSubManager *psm, UA_SecurityGroup *sg);

#endif /* UA_ENABLE_PUBSUB_SKS */

/******************/
/* PubSub Manager */
/******************/

typedef enum {
    UA_WRITER_GROUP = 0,
    UA_DATA_SET_WRITER = 1,
} UA_ReserveIdType;

typedef struct UA_ReserveId {
    UA_UInt16 id;
    UA_ReserveIdType reserveIdType;
    UA_String transportProfileUri;
    UA_NodeId sessionId;
    ZIP_ENTRY(UA_ReserveId) treeEntry;
} UA_ReserveId;

typedef ZIP_HEAD(UA_ReserveIdTree, UA_ReserveId) UA_ReserveIdTree;

struct UA_PubSubManager {
    UA_ServerComponent sc;

    UA_Logger *logging; /* shortcut to sc->server.logging */

    UA_UInt64 defaultPublisherId;
    /* Connections and PublishedDataSets can exist alone (own lifecycle) -> top
     * level components */
    size_t connectionsSize;
    TAILQ_HEAD(, UA_PubSubConnection) connections;

    size_t publishedDataSetsSize;
    TAILQ_HEAD(, UA_PublishedDataSet) publishedDataSets;

    size_t subscribedDataSetsSize;
    TAILQ_HEAD(, UA_SubscribedDataSet) subscribedDataSets;

    size_t reserveIdsSize;
    UA_ReserveIdTree reserveIds;

    /* During the initial activation of the PubSub subsystem (e.g. when loading a configuration file), special behaviour
     * is required within the PubSub state machine transitions. This global flag can be set to indicate that the
     * configuration phase is active, and it is evaluated during the state changes of the PubSub components. */
    UA_Boolean pubSubInitialSetupMode;

#ifdef UA_ENABLE_PUBSUB_SKS
    LIST_HEAD(, UA_PubSubKeyStorage) pubSubKeyList;

    size_t securityGroupsSize;
    TAILQ_HEAD(, UA_SecurityGroup) securityGroups;
#endif

#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    UA_UInt32 uniqueIdCount;
#endif
};

static UA_INLINE UA_PubSubManager *
getPSM(UA_Server *server) {
    return (UA_PubSubManager*)getServerComponentByName(server, UA_STRING("pubsub"));
}

UA_StatusCode
UA_PubSubManager_clear(UA_PubSubManager *psm);

void
UA_PubSubManager_setState(UA_PubSubManager *psm,
                          UA_LifecycleState state);

UA_StatusCode
UA_PubSubManager_reserveIds(UA_PubSubManager *psm, UA_NodeId sessionId,
                            UA_UInt16 numRegWriterGroupIds,
                            UA_UInt16 numRegDataSetWriterIds,
                            UA_String transportProfileUri, UA_UInt16 **writerGroupIds,
                            UA_UInt16 **dataSetWriterIds);

void
UA_PubSubManager_freeIds(UA_PubSubManager *psm);

#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
void
UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId);
#endif

UA_Guid
UA_PubSubManager_generateUniqueGuid(UA_PubSubManager *psm);

UA_UInt32
UA_PubSubConfigurationVersionTimeDifference(UA_DateTime now);

/************************************/
/* Information Model Representation */
/************************************/

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */

UA_StatusCode
initPubSubNS0(UA_Server *server);

#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
initPubSubNS0_SKS(UA_Server *server);
#endif

UA_StatusCode
addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection);

UA_StatusCode
addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);

UA_StatusCode
addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup);

UA_StatusCode
addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter);

UA_StatusCode
addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet);

UA_StatusCode
addSubscribedDataSetRepresentation(UA_Server *server, UA_SubscribedDataSet *subscribedDataSet);

UA_StatusCode
addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader);

UA_StatusCode
connectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId, UA_NodeId sdsId);

void
disconnectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId);

#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
addSecurityGroupRepresentation(UA_Server *server, UA_SecurityGroup *securityGroup);
#endif /* UA_ENABLE_PUBSUB_SKS */

#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */

/* Recursively check whether a data type contains String or ByteString
 * members. Used to warn about RawData encoding where maxStringLength
 * padding is not applied for strings inside structures. */
static UA_INLINE UA_Boolean
typeContainsString(const UA_DataType *type, size_t depth) {
    if(!type || depth > 10)
        return false;
    if(type->typeKind == UA_DATATYPEKIND_STRING ||
       type->typeKind == UA_DATATYPEKIND_BYTESTRING)
        return true;
    if(type->typeKind != UA_DATATYPEKIND_STRUCTURE &&
       type->typeKind != UA_DATATYPEKIND_OPTSTRUCT &&
       type->typeKind != UA_DATATYPEKIND_UNION)
        return false;
    if(type->pointerFree)
        return false;
    for(size_t i = 0; i < type->membersSize; i++) {
        if(typeContainsString(type->members[i].memberType, depth + 1))
            return true;
    }
    return false;
}

#endif /* UA_ENABLE_PUBSUB */

_UA_END_DECLS


/**** amalgamated original file "/src/pubsub/ua_pubsub_keystorage.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2019 ifak e.V. Magdeburg (Holger Zipper)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */

#ifndef UA_PUBSUB_KEYSTORAGE
#define UA_PUBSUB_KEYSTORAGE


_UA_BEGIN_DECLS

#ifdef UA_ENABLE_PUBSUB_SKS


/**
 * PubSubKeyStorage
 * ================
 * A PubSubKeyStorage provides a linked list to store all the keys used to
 * secure the messages. It keeps the records of old keys (past keys), current
 * key, new keys (futurekeys), time to move to next key and callback id.
 *
 * PubSubKeyListItem is the basic item stored in the KeyList of KeyStorage. It
 * provides keyId, Key, and pointer to the next key in KeyList. The KeyId is used
 * to identify and update currentKey in the keystorage. The KeyId is the SecurityTokenId
 * that appears in the header of messages secured with the CurrentKey.
 *
 * Working
 * =======
 *                     +------------------------------+
 *                     |AddReaderGroup/AddWriterGroup |
 *                     +------------------------------+
 *                                    |
 *                                    V
 *                     +--------------------+
 *                     |CheckSecurityGroupId|
 *                     +--------------------+
 *                                    |Yes
 *                                    V
 *                     +--------------------+
 *                     |InitializeKeyStorage|
 *                     +--------------------+
 *                                    |
 *                                    V
 *                     +----------------------------+
 *                     |store/updateKeysInKeyStorage|
 *                     +----------------------------+
 *                                    |
 *                                    V
 *                     +------------------------------------------+
 *                     |activateKeysToAllPubSubGroupChannelContext|
 *                     +------------------------------------------+
 *                                    |                        Ʌ
 *                                    V                        |
 *                     +-----------------------+               |
 *                     |addKeyRolloverCallbacks|               |
 *                     +-----------------------+               |
 *                                    |                        |
 *                                    V                        |
 *                     +-------------------+                   |
 *                     |keyRolloverCallback|                   |
 *                     +-------------------+                   |
 *                                    |CurrentKey!=LastItem    |
 *                                    -------------------------+
 *
 * A KeyStorage is created and initialized when a ReaderGroup or WriterGroup is
 * created with securityGroupId and SecurityMode SignAndEncrypt. The new
 * KeyStorage is added to the server KeyStorageList. At this time KeyList is empty.
 *
 * UA_PubSubKeyStorage_storeSecurityKeys is used to push the keys into existing
 * keystorage. In order to update the KeyList of an existing keyStorage,
 * UA_PubSubKeyStorage_update is called.
 *
 * After adding/updating the keys to keystorage, the current key should be
 * activated to the associated PubSub Group's ChannelContext in the server. The
 * security Policy associated with PubSub Group will take the keys from
 * channel context and use them to secure the messages.
 * The UA_PubSubKeyStorage_storeSecurityKeys and UA_PubSubKeyStorage_update
 * method will be used by setSecurityKeysAction and getSecurityKeysAction to
 * retrieve the keys from SKS server and store keys in local storage.
 *
 * Each key has a life time, after which the current key is expired and move to
 * next key in the existing list. For this a callback function is added to the
 * server. The callback function keyRolloverCallback is added to the server as a
 * timed callback. The addKeyRolloverCallbacks function calculates the time
 * stamp to trigger the callback when the current Key expires and roll
 * over to the next key in existing list.
 *
 */

/**
 * @brief This structure holds the information about the keys
 */
typedef struct UA_PubSubKeyListItem {
    /* The SecurityTokenId associated with Key*/
    UA_UInt32 keyID;

    /* This key is not used directly since the protocol associated with the
     * PubSubGroup(s) specifies an algorithm to generate distinct keys for
     * different types of cryptography operations*/
    UA_ByteString key;

    /* Pointers to the key list entries*/
    TAILQ_ENTRY(UA_PubSubKeyListItem) keyListEntry;
} UA_PubSubKeyListItem;

/* Queue Definition*/
typedef TAILQ_HEAD(keyListItems, UA_PubSubKeyListItem) keyListItems;

/* Used to hold configuration information required to connect an SKS server and
 * fetch the security keys */
typedef struct UA_PubSubSKSConfig {
    UA_ClientConfig clientConfig;
    const char *endpointUrl;
    UA_Server_sksPullRequestCallback userNotifyCallback;
    void *context;
    UA_UInt32 reqId;
} UA_PubSubSKSConfig;

/* Holds all info and keys related to one SecurityGroup */
struct UA_PubSubKeyStorage {

    /* Security group id of the security group related to this storage */
    UA_String securityGroupID;

    /* Non-owning pointer to the security policy related to this storage */
    UA_PubSubSecurityPolicy *policy;

    /* In case of the SKS server, the key storage structure is deleted when
     * removing the security group. in case of publisher / subscriber, one key
     * storage structure is referenced by multiple reader / writer groups have a
     * reference count to manage free */
    UA_UInt32 referenceCount;

    /* Array of keys. the elements inside this array have a next pointer.
     * keyList can therefore be used as linked list. */
    keyListItems keyList;
    size_t keyListSize;

    /* Maximum number of past keys a keystorage is allowed to store */
    UA_UInt32 maxPastKeyCount;

    /* Maximum number of Future keys a keyStorage is allowed to store */
    UA_UInt32 maxFutureKeyCount;

    /* Maximum keylist size, calculated from maxPastKeyCount and
     * maxFutureKeyCount */
    UA_UInt32 maxKeyListSize;

    /* The SecurityTokenId that appears in the header of messages secured with
     * the CurrentKey. It starts at 1 and is incremented by 1 each time the
     * KeyLifetime elapses even if no keys are requested. If the CurrentTokenId
     * increments past the maximum value of UInt32 it restarts a 1. */
    UA_UInt32 currentTokenId;

    /* The current key used to secure the messages */
    UA_PubSubKeyListItem *currentItem;

    /* KeyLifeTime used to update the CurrentKey from the Local KeyStorage */
    UA_Duration keyLifeTime;

    /* Id used to register the callback to retrieve the keys related to this
     * security group */
    UA_UInt64 callBackId;

    /* Sks related information to connect with SKS server and fetch security
     * keys */
    UA_PubSubSKSConfig sksConfig;

    /* Pointer to the key storage list */
    LIST_ENTRY(UA_PubSubKeyStorage) keyStorageList;

};

/**
 * @brief Find the Keystorage from the KeyStorageList and returns the pointer to
 * the keystorage
 *
 * @param psm holds the keystoragelist
 * @param securityGroupId of the keystorage to be found
 * @return Pointer to the keystorage on success, null pointer on failure
 */
UA_PubSubKeyStorage *
UA_PubSubKeyStorage_find(UA_PubSubManager *psm, UA_String securityGroupId);

/**
 * @brief retreives the security policy pointer from the PubSub configuration by
 * SecurityPolicyUri
 *
 * @param psm the PubSubManager
 * @param securityPolicyUri the URI of the security policy
 * @param policy the pointer to the security policy
 * @return UA_StatusCode return status code
 */
UA_PubSubSecurityPolicy *
findPubSubSecurityPolicy(UA_PubSubManager *psm,
                         const UA_String *securityPolicyUri);

/**
 * @brief Deletes the keystorage from the server and its members
 *
 * @param psm the PubSubManager
 * @param keyStorage pointer to the keystorage
 */
void
UA_PubSubKeyStorage_delete(UA_PubSubManager *psm,
                           UA_PubSubKeyStorage *keyStorage);

/**
 * @brief Initializes an empty Keystorage for the SecurityGroupId and add it to the Server
 * KeyStorageList
 *
 * @param psm the PubSubManager
 * @param keyStorage Pointer to the keystorage to be initialized
 * @param securityGroupId The identifier of the SecurityGroup
 * @param policy The security policy assocaited with the security algorithm
 * @param maxPastKeyCount maximum number of past keys a keystorage is allowed to store
 * @param maxFutureKeyCount maximum number of future keys a keystorage is allowed to store
 * @return UA_StatusCode return status code
 */
UA_StatusCode
UA_PubSubKeyStorage_init(UA_PubSubManager *psm,
                         UA_PubSubKeyStorage *keyStorage,
                         const UA_String *securityGroupId,
                         UA_PubSubSecurityPolicy *policy,
                         UA_UInt32 maxPastKeyCount, UA_UInt32 maxFutureKeyCount);

void
UA_PubSubKeyStorage_clearKeyList(UA_PubSubKeyStorage *ks);

/**
 * @brief Add keys tot the key storage. Generates the keyId internally. They get
 * appended to the end of the list. This method DOES NOT VALIDATE the
 * maxKeyListSize property! Do this before.
 *
 * @param keyStorage pointer to the keyStorage
 * @param keysSize the number of keys provided
 * @param keys pointer to the keys
 * @param currentKeyId The new keyIds start at currentKeyId + 1
 * @return UA_StatusCode the return status
 */
UA_StatusCode
UA_PubSubKeyStorage_addSecurityKeys(UA_PubSubKeyStorage *keyStorage, size_t keysSize,
                                    UA_ByteString *keys, UA_UInt32 currentKeyId);

/* Fetch the key from the list and set it as the current key */
UA_StatusCode
UA_PubSubKeyStorage_setCurrentKey(UA_PubSubKeyStorage *keyStorage,
                                  UA_UInt32 keyId);

/**
 * @brief Finds the KeyItem from the KeyList by KeyId
 *
 * @param keyStorage pointer to the keystorage
 * @param keyId the identifier of the Key
 * @return NULL or the found item
 */
UA_PubSubKeyListItem *
UA_PubSubKeyStorage_getKeyByKeyId(UA_PubSubKeyStorage *keyStorage,
                                  const UA_UInt32 keyId);

/**
 * @brief Adds a new KeyItem at the end of the KeyList
 * to the new KeyListItem.
 *
 * @param keyStorage pointer to the keystorage
 * @param key the key to be added
 * @param keyID the keyID associated with the key to be added
 */
UA_PubSubKeyListItem *
UA_PubSubKeyStorage_push(UA_PubSubKeyStorage *keyStorage, const UA_ByteString *key,
                         UA_UInt32 keyID);

/**
 * @brief It calculates the time to trigger the callback to update current key, adds the
 * callback to the server and returns the callbackId.
 *
 * @param psm the PubSubManager
 * @param keyStorage the pointer to the existing keystorage in the server
 * @param callback the callback function to be added to the server
 * @param timeToNextMs time in milli seconds to trigger the callback function
 * @param callbackID the returned callbackId of the added callback function
 * @return UA_StatusCode the return status
 */
UA_StatusCode
UA_PubSubKeyStorage_addKeyRolloverCallback(UA_PubSubManager *psm,
                                           UA_PubSubKeyStorage *keyStorage,
                                           UA_Callback callback,
                                           UA_Duration timeToNextMs,
                                           UA_UInt64 *callbackID);

/**
 * @brief It takes the current Key data, divide it into signing key, encrypting key and
 * keyNonce according to security policy associated with PubSub Group and set it in
 * channel context of the assocaited PubSub Group. In case of pubSubGroupId is
 * UA_NODEID_NULL, all the Reader/WriterGroup's channelcontext are updated with matching
 * SecurityGroupId.
 *
 * @param psm the PubSubManager
 * @param pubSubGroupId the nodeId of the Reader/WirterGroup whose channel context to be
 * updated
 * @param securityGroupId The identifier for the SecurityGroup
 * @return UA_StatusCode return status code
 */
UA_StatusCode
UA_PubSubKeyStorage_activateKeyToChannelContext(UA_PubSubManager *psm,
                                                const UA_NodeId pubSubGroupId,
                                                const UA_String securityGroupId);

/**
 * @brief The callback function to update the current key from keystorage in the server
 * and activate the current key into channel context of the associated PubSub Group
 *
 * @param psm the PubSubManager
 * @param keyStorage the pointer to the keystorage
 */
void
UA_PubSubKeyStorage_keyRolloverCallback(UA_PubSubManager *psm,
                                        UA_PubSubKeyStorage *keyStorage);

/* KeyStorage must be referenced by atleast one PubSubGroup. This method reduces
 * the reference count by one. If no PubSubGroup uses the key storage, then it
 * is deleted. */
void
UA_PubSubKeyStorage_detachKeyStorage(UA_PubSubManager *psm,
                                     UA_PubSubKeyStorage *keyStorage);

/* Calls get SecurityKeys Method and Store the returned keys into KeyStorage */
UA_StatusCode
getSecurityKeysAndStoreFetchedKeys(UA_PubSubManager *psm,
                                   UA_PubSubKeyStorage *keyStorage);

#endif

_UA_END_DECLS

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/deps/yxml.h" ****/

/* Copyright (c) 2013-2014 Yoran Heling

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:

  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef YXML_H
#define YXML_H

#include <stdint.h>
#include <stddef.h>

#if defined(_MSC_VER) && !defined(__cplusplus) && !defined(inline)
#define inline __inline
#endif

/* Full API documentation for this library can be found in the "yxml.md" file
 * in the yxml git repository, or online at http://dev.yorhel.nl/yxml/man */

typedef enum {
	YXML_EEOF        = -5, /* Unexpected EOF                             */
	YXML_EREF        = -4, /* Invalid character or entity reference (&whatever;) */
	YXML_ECLOSE      = -3, /* Close tag does not match open tag (<Tag> .. </OtherTag>) */
	YXML_ESTACK      = -2, /* Stack overflow (too deeply nested tags or too long element/attribute name) */
	YXML_ESYN        = -1, /* Syntax error (unexpected byte)             */
	YXML_OK          =  0, /* Character consumed, no new token present   */
	YXML_ELEMSTART   =  1, /* Start of an element:   '<Tag ..'           */
	YXML_CONTENT     =  2, /* Element content                            */
	YXML_ELEMEND     =  3, /* End of an element:     '.. />' or '</Tag>' */
	YXML_ATTRSTART   =  4, /* Attribute:             'Name=..'           */
	YXML_ATTRVAL     =  5, /* Attribute value                            */
	YXML_ATTREND     =  6, /* End of attribute       '.."'               */
	YXML_PISTART     =  7, /* Start of a processing instruction          */
	YXML_PICONTENT   =  8, /* Content of a PI                            */
	YXML_PIEND       =  9  /* End of a processing instruction            */
} yxml_ret_t;

/* When, exactly, are tokens returned?
 *
 * <TagName
 *   '>' ELEMSTART
 *   '/' ELEMSTART, '>' ELEMEND
 *   ' ' ELEMSTART
 *     '>'
 *     '/', '>' ELEMEND
 *     Attr
 *       '=' ATTRSTART
 *         "X ATTRVAL
 *           'Y'  ATTRVAL
 *             'Z'  ATTRVAL
 *               '"' ATTREND
 *                 '>'
 *                 '/', '>' ELEMEND
 *
 * </TagName
 *   '>' ELEMEND
 */

typedef struct {
	/* PUBLIC (read-only) */

	/* Name of the current element, zero-length if not in any element. Changed
	 * after YXML_ELEMSTART. The pointer will remain valid up to and including
	 * the next non-YXML_ATTR* token, the pointed-to buffer will remain valid
	 * up to and including the YXML_ELEMEND for the corresponding element. */
	char *elem;

	/* The last read character(s) of an attribute value (YXML_ATTRVAL), element
	 * data (YXML_CONTENT), or processing instruction (YXML_PICONTENT). Changed
	 * after one of the respective YXML_ values is returned, and only valid
	 * until the next yxml_parse() call. Usually, this string only consists of
	 * a single byte, but multiple bytes are returned in the following cases:
	 * - "<?SomePI ?x ?>": The two characters "?x"
	 * - "<![CDATA[ ]x ]]>": The two characters "]x"
	 * - "<![CDATA[ ]]x ]]>": The three characters "]]x"
	 * - "&#N;" and "&#xN;", where dec(n) > 127. The referenced Unicode
	 *   character is then encoded in multiple UTF-8 bytes.
	 */
	char data[8];

	/* Name of the current attribute. Changed after YXML_ATTRSTART, valid up to
	 * and including the next YXML_ATTREND. */
	char *attr;

	/* Name/target of the current processing instruction, zero-length if not in
	 * a PI. Changed after YXML_PISTART, valid up to (but excluding)
	 * the next YXML_PIEND. */
	char *pi;

	/* Line number, byte offset within that line, and total bytes read. These
	 * values refer to the position _after_ the last byte given to
	 * yxml_parse(). These are useful for debugging and error reporting. */
	uint64_t byte;
	uint64_t total;
	uint32_t line;

	/* PRIVATE */
	int state;
	unsigned char *stack; /* Stack of element names + attribute/PI name, separated by \0. Also starts with a \0. */
	size_t stacksize, stacklen;
	unsigned reflen;
	unsigned quote;
	int nextstate; /* Used for '@' state remembering and for the "string" consuming state */
	unsigned ignore;
	unsigned char *string;
} yxml_t;

#ifdef __cplusplus
extern "C" {
#endif

void yxml_init(yxml_t *, void *, size_t);

yxml_ret_t yxml_parse(yxml_t *, int);

/* May be called after the last character has been given to yxml_parse().
 * Returns YXML_OK if the XML document is valid, YXML_EEOF otherwise.  Using
 * this function isn't really necessary, but can be used to detect documents
 * that don't end correctly. In particular, an error is returned when the XML
 * document did not contain a (complete) root element, or when the document
 * ended while in a comment or processing instruction. */
yxml_ret_t yxml_eof(yxml_t *);

#ifdef __cplusplus
}
#endif

/* Returns the length of the element name (x->elem), attribute name (x->attr),
 * or PI name (x->pi). This function should ONLY be used directly after the
 * YXML_ELEMSTART, YXML_ATTRSTART or YXML_PISTART (respectively) tokens have
 * been returned by yxml_parse(), calling this at any other time may not give
 * the correct results. This function should also NOT be used on strings other
 * than x->elem, x->attr or x->pi. */
static inline size_t yxml_symlen(yxml_t *x, const char *s) {
	return (size_t)((x->stack + x->stacklen) - (const unsigned char*)s);
}

#endif /* YXML_H */

/**** amalgamated original file "/src/ua_types_encoding_xml.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */




_UA_BEGIN_DECLS

#define UA_XML_MAXMEMBERSCOUNT 256
#define UA_XML_ENCODING_MAX_RECURSION 100

/* XML input gets parsed into a sequence of tokens first.
 * Processing isntructions, etc. get ignored. */

typedef enum {
    XML_TOKEN_ELEMENT = 0,
    XML_TOKEN_ATTRIBUTE,
} xml_token_type;

typedef struct {
    xml_token_type type;
    UA_String name;
    UA_String content;
    unsigned attributes; // For elements only: the number of attributes
    unsigned children;   // For elements only: the number of child elements
    unsigned start;      // First character of the token in the xml
    unsigned end;        // Position after the token ends
} xml_token;

typedef enum {
    XML_ERROR_NONE = 0,
    XML_ERROR_INVALID,   // Invalid character/syntax
    XML_ERROR_OVERFLOW   // Token buffer overflow
} xml_error_code;

typedef struct {
    xml_error_code error;
    unsigned int error_pos;
    unsigned int num_tokens;
    const xml_token *tokens;
} xml_result;

/* Parse XML input into a token sequence */
xml_result
xml_tokenize(const char *xml, unsigned int len,
             xml_token *tokens, unsigned int max_tokens);

typedef struct {
    uint8_t *pos;
    const uint8_t *end;
    uint16_t depth; /* How often did we encoding recurse? */
    UA_Boolean calcOnly; /* Only compute the length of the decoding */
    const UA_DataTypeArray *customTypes;

    UA_NamespaceMapping *namespaceMapping;
    const UA_String *serverUris;
    size_t serverUrisSize;
} CtxXml;

typedef struct {
    size_t index;
    size_t depth;
    size_t tokensSize;
    xml_token *tokens;
    const UA_DataTypeArray *customTypes;
    const char *xml;

    UA_NamespaceMapping *namespaceMapping;
    const UA_String *serverUris;
    size_t serverUrisSize;
} ParseCtxXml;

typedef UA_StatusCode
(*encodeXmlSignature)(CtxXml *ctx, const void *src, const UA_DataType *type);

typedef UA_StatusCode
(*decodeXmlSignature)(ParseCtxXml *ctx, void *dst, const UA_DataType *type);

/* Expose the jump tables and some methods */
extern const encodeXmlSignature encodeXmlJumpTable[UA_DATATYPEKINDS];
extern const decodeXmlSignature decodeXmlJumpTable[UA_DATATYPEKINDS];

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_discovery.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 */



_UA_BEGIN_DECLS

#ifdef UA_ENABLE_DISCOVERY

#ifdef UA_ENABLE_DISCOVERY
struct UA_DiscoveryManager;
typedef struct UA_DiscoveryManager UA_DiscoveryManager;
#endif

typedef struct registeredServer {
    LIST_ENTRY(registeredServer) pointers;
    UA_RegisteredServer registeredServer;
    UA_DateTime lastSeen;
} registeredServer;

/* Store async register service calls. So we can cancel outstanding requests
 * during shutdown. */
typedef struct {
    UA_DelayedCallback cleanupCallback; /* delayed cleanup */
    UA_Server *server;
    UA_DiscoveryManager *dm;
    UA_Client *client;
    UA_String semaphoreFilePath;
    UA_Boolean unregister;

    UA_Boolean register2;
    UA_Boolean shutdown;
    UA_Boolean connectSuccess;
} asyncRegisterRequest;
#define UA_MAXREGISTERREQUESTS 4

struct UA_DiscoveryManager {
    UA_ServerComponent sc;

    UA_UInt64 discoveryCallbackId;

    /* Outstanding requests. So they can be cancelled during shutdown. */
    asyncRegisterRequest registerRequests[UA_MAXREGISTERREQUESTS];

    LIST_HEAD(, registeredServer) registeredServers;
    size_t registeredServersSize;
    UA_Server_registerServerCallback registerServerCallback;
    void* registerServerCallbackData;

# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_Boolean mdnsMainSrvAdded;
    UA_Server_serverOnNetworkCallback serverOnNetworkCallback;
    void *serverOnNetworkCallbackData;
#  ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD
    UA_ConnectionManager *cm;
#  endif
# endif /* UA_ENABLE_DISCOVERY_MULTICAST */
};

void
UA_DiscoveryManager_setState(UA_DiscoveryManager *dm,
                             UA_LifecycleState state);

#ifdef UA_ENABLE_DISCOVERY_MULTICAST

/* Sends out a new mDNS package for the given server data. This Method is
 * normally called when another server calls the RegisterServer Service on this
 * server. Then this server is responsible to send out a new mDNS package to
 * announce it.
 *
 * Additionally this method also adds the given server to the internal
 * serversOnNetwork list so that a client finds it when calling
 * FindServersOnNetwork. */
void
UA_Discovery_updateMdnsForDiscoveryUrl(UA_DiscoveryManager *dm, const UA_String serverName,
                                       const UA_MdnsDiscoveryConfiguration *mdnsConfig,
                                       const UA_String discoveryUrl, UA_Boolean isOnline,
                                       UA_Boolean updateTxt);

void UA_DiscoveryManager_startMulticast(UA_DiscoveryManager *dm);
void UA_DiscoveryManager_stopMulticast(UA_DiscoveryManager *dm);

void
UA_DiscoveryManager_clearMdns(UA_DiscoveryManager *dm);

UA_UInt32
UA_DiscoveryManager_getMdnsConnectionCount(void);

UA_UInt32
UA_DiscoveryManager_getServerOnNetworkRecordIdCounter(UA_DiscoveryManager *dm);

UA_StatusCode
UA_DiscoveryManager_resetServerOnNetworkRecordCounter(UA_DiscoveryManager *dm);

UA_DateTime
UA_DiscoveryManager_getServerOnNetworkCounterResetTime(UA_DiscoveryManager *dm);

UA_ServerOnNetwork*
UA_DiscoveryManager_getServerOnNetworkList(UA_DiscoveryManager *dm);

UA_ServerOnNetwork*
UA_DiscoveryManager_getNextServerOnNetworkRecord(UA_DiscoveryManager *dm,
                                  UA_ServerOnNetwork *current);

UA_StatusCode
UA_DiscoveryManager_clearServerOnNetwork(UA_DiscoveryManager *dm);

void
UA_DiscoveryManager_mdnsCyclicTimer(UA_Server *server, void *data);

#endif /* UA_ENABLE_DISCOVERY_MULTICAST */

#endif /* UA_ENABLE_DISCOVERY */

_UA_END_DECLS


/**** amalgamated original file "/src/ua_types.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2016-2017 (c) Florian Palm
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014 (c) Leon Urbas
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Markus Graube
 *    Copyright 2015 (c) Reza Ebrahimi
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 */



#define UA_MAX_ARRAY_DIMS 100 /* Max dimensions of an array */

/* Datatype Handling
 * -----------------
 * This file contains handling functions for the builtin types and functions
 * handling of structured types and arrays. These need type descriptions in a
 * UA_DataType structure. The UA_DataType structures as well as all non-builtin
 * datatypes are autogenerated. */

/* Global definition of NULL type instances. These are always zeroed out, as
 * mandated by the C/C++ standard for global values with no initializer. */
const UA_String UA_STRING_NULL = {0, NULL};
const UA_ByteString UA_BYTESTRING_NULL = {0, NULL};
const UA_Guid UA_GUID_NULL = {0, 0, 0, {0,0,0,0,0,0,0,0}};
const UA_NodeId UA_NODEID_NULL = {0, UA_NODEIDTYPE_NUMERIC, {0}};
const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {{0, UA_NODEIDTYPE_NUMERIC, {0}}, {0, NULL}, 0};

typedef UA_StatusCode
(*UA_copySignature)(const void *src, void *dst, const UA_DataType *type);
extern const UA_copySignature copyJumpTable[UA_DATATYPEKINDS];

typedef void (*UA_clearSignature)(void *p, const UA_DataType *type);
extern const UA_clearSignature clearJumpTable[UA_DATATYPEKINDS];

typedef UA_Order
(*UA_orderSignature)(const void *p1, const void *p2, const UA_DataType *type);
extern const UA_orderSignature orderJumpTable[UA_DATATYPEKINDS];

static UA_Order
nodeIdOrder(const UA_NodeId *p1, const UA_NodeId *p2, const UA_DataType *_);
static UA_Order
expandedNodeIdOrder(const UA_ExpandedNodeId *p1, const UA_ExpandedNodeId *p2,
                    const UA_DataType *_);
static UA_Order
guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *_);

const UA_DataType *
UA_findDataTypeWithCustom(const UA_NodeId *typeId,
                          const UA_DataTypeArray *customTypes) {
    /* Always look in built-in types first (may contain data types from all
     * namespaces).
     *
     * TODO: The standard-defined types are ordered. See if binary search is
     * more efficient. */
    for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
        if(nodeIdOrder(&UA_TYPES[i].typeId, typeId, NULL) == UA_ORDER_EQ)
            return &UA_TYPES[i];
    }

    /* Search in the customTypes */
    while(customTypes) {
        for(size_t i = 0; i < customTypes->typesSize; ++i) {
            if(nodeIdOrder(&customTypes->types[i].typeId, typeId, NULL) == UA_ORDER_EQ)
                return &customTypes->types[i];
        }
        customTypes = customTypes->next;
    }

    return NULL;
}

const UA_DataType *
UA_findDataType(const UA_NodeId *typeId) {
    return UA_findDataTypeWithCustom(typeId, NULL);
}

#ifdef UA_ENABLE_TYPEDESCRIPTION
const UA_DataType *
UA_findDataTypeByName(const UA_QualifiedName *qn) {
    UA_Byte nameBuf[512];
    UA_String name = {511, nameBuf};
    UA_StatusCode res = UA_QualifiedName_print(qn, &name);
    name.data[name.length] = 0;
    if(res != UA_STATUSCODE_GOOD)
        return NULL;
    for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
        if(strcmp((char*)nameBuf, UA_TYPES[i].typeName) == 0)
            return &UA_TYPES[i];
    }
    return NULL;
}
#endif

void
UA_DataType_clear(UA_DataType *type) {
#ifdef UA_ENABLE_TYPEDESCRIPTION
    UA_free((void*)(uintptr_t)type->typeName);
    for(size_t j = 0; j < type->membersSize; ++j) {
        UA_DataTypeMember *m = &type->members[j];
        UA_free((void*)(uintptr_t)m->memberName);
    }
#endif
    UA_NodeId_clear(&type->typeId);
    UA_NodeId_clear(&type->binaryEncodingId);
    UA_NodeId_clear(&type->xmlEncodingId);
    UA_free(type->members);
    memset(type, 0, sizeof(UA_DataType));
}

UA_StatusCode
UA_DataType_copy(const UA_DataType *t1, UA_DataType *t2) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(t2, t1, sizeof(UA_DataType));
    t2->members = NULL;
    t2->membersSize = 0;

    /* Copy the typename */
#ifdef UA_ENABLE_TYPEDESCRIPTION
    size_t nameLen = strlen(t1->typeName) + 1;
    char *t2Name = (char*)UA_malloc(nameLen);
    if(!t2Name) {
        res = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }
    memcpy(t2Name, t1->typeName, nameLen);
    *(void**)(uintptr_t)&t2->typeName = t2Name;
#endif


    /* Copy the members */
    if(t1->membersSize > 0) {
        t2->members = (UA_DataTypeMember*)
            UA_calloc(t1->membersSize, sizeof(UA_DataTypeMember));
        if(!t2->members) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
            goto errout;
        }
        for(size_t i = 0; i < t1->membersSize; i++) {
            const UA_DataTypeMember *m1 = &t1->members[i];
            UA_DataTypeMember *m2 = &t2->members[i];
            memcpy(m2, m1, sizeof(UA_DataTypeMember));
#ifdef UA_ENABLE_TYPEDESCRIPTION
            nameLen = strlen(m1->memberName) + 1;
            char *mName = (char*)UA_malloc(nameLen);
            if(!mName) {
                res = UA_STATUSCODE_BADOUTOFMEMORY;
                goto errout;
            }
            memcpy(mName, m1->memberName, nameLen);
            *(void**)(uintptr_t)&m2->memberName = mName;
#endif
        }
        t2->membersSize = t1->membersSize;
    }

 errout:
    if(res != UA_STATUSCODE_GOOD)
        UA_DataType_clear(t2);
    return res;
}

void
UA_cleanupDataTypeWithCustom(UA_DataTypeArray *customTypes) {
    while(customTypes) {
        UA_DataTypeArray *next = customTypes->next;
        if(customTypes->cleanup) {
            for(size_t i = 0; i < customTypes->typesSize; ++i) {
                UA_DataType *type = &customTypes->types[i];
                UA_DataType_clear(type);
            }
            UA_free(customTypes->types);
            UA_free(customTypes);
        }
        customTypes = next;
    }
}

/*****************/
/* Builtin Types */
/*****************/

UA_Boolean
UA_StatusCode_isBad(UA_StatusCode code) {
    return ((code >> 30) >= 0x02);
}

UA_Boolean
UA_StatusCode_isUncertain(UA_StatusCode code) {
    return ((code >> 30) == 0x01);
}

UA_Boolean
UA_StatusCode_isGood(UA_StatusCode code) {
    return ((code >> 30) == 0x00);
}

UA_Boolean
UA_StatusCode_equalTop(UA_StatusCode s1, UA_StatusCode s2) {
    return ((s1 & 0xFFFF0000) == (s2 & 0xFFFF0000));
}

UA_String
UA_STRING(char *chars) {
    UA_String s = {0, NULL};
    if(!chars)
        return s;
    s.length = strlen(chars);
    s.data = (UA_Byte*)chars;
    return s;
}

UA_String
UA_String_fromChars(const char *src) {
    UA_String s; s.length = 0; s.data = NULL;
    if(!src)
        return s;
    s.length = strlen(src);
    if(s.length > 0) {
        s.data = (u8*)UA_malloc(s.length);
        if(UA_UNLIKELY(!s.data)) {
            s.length = 0;
            return s;
        }
        memcpy(s.data, src, s.length);
    } else {
        s.data = (u8*)UA_EMPTY_ARRAY_SENTINEL;
    }
    return s;
}

UA_Boolean
UA_String_isEmpty(const UA_String *s) {
    return (s->length == 0 || s->data == NULL);
}

static UA_Byte
lowercase(UA_Byte c) {
    if(((int)c) - 'A' < 26) return c | 32;
    return c;
}

static int
casecmp(const UA_Byte *l, const UA_Byte *r, size_t n) {
    if(!n--) return 0;
    for(; *l && *r && n && (*l == *r || lowercase(*l) == lowercase(*r)); l++, r++, n--);
    return lowercase(*l) - lowercase(*r);
}

/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles
 * ASCII strings, and not UTF8! */
UA_Boolean
UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2) {
    if(s1->length != s2->length)
        return false;
    if(s1->length == 0)
        return true;
    if(s2->data == NULL)
        return false;

    return casecmp(s1->data, s2->data, s1->length) == 0;
}

static UA_StatusCode
String_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_String *srcS = (const UA_String*)src;
    UA_String *dstS = (UA_String *)dst;
    UA_StatusCode res =
        UA_Array_copy(srcS->data, srcS->length, (void**)&dstS->data,
                      &UA_TYPES[UA_TYPES_BYTE]);
    if(res == UA_STATUSCODE_GOOD)
        dstS->length = srcS->length;
    return res;
}

static void
String_clear(void *p, const UA_DataType *_) {
    UA_String *s = (UA_String*)p;
    UA_Array_delete(s->data, s->length, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
UA_String_append(UA_String *s, const UA_String s2) {
    if(s2.length == 0)
        return UA_STATUSCODE_GOOD;
    UA_Byte *buf = (UA_Byte*)UA_realloc(s->data, s->length + s2.length);
    if(!buf)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memcpy(buf + s->length, s2.data, s2.length);
    s->data = buf;
    s->length += s2.length;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_String_format(UA_String *str, const char *format, ...) {
    va_list args;
    va_start(args, format);
    UA_StatusCode ret = UA_String_vprintf(str, format, args);
    va_end(args);
    return ret;
}

UA_StatusCode
UA_String_vformat(UA_String *str, const char *format, va_list args) {
    /* Store a copy of the arguments for the second pass. va_list cannot be
     * iterated twice. */
    va_list args2;
    va_copy(args2, args);

    /* Encode initially */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    int out = mp_vsnprintf((char*)str->data, str->length, format, args);
    if(out < 0) {
        res = UA_STATUSCODE_BADENCODINGERROR;
        goto errout;
    }

    /* Output length zero */
    if(out == 0) {
        str->length = 0;
        if(str->data == NULL)
            str->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        goto errout;
    }

    /* Encode into existing buffer. mp_snprintf adds a trailing \0. So out must
     * be truly smaller than str->length for success. */
    if(str->length > 0) {
        if((size_t)out < str->length) {
            str->length = (size_t)out;
        } else {
            res = UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        }
        goto errout;
    }

    /* Allocate and encode again (+1 length for the trailing \0) */
    res = UA_ByteString_allocBuffer(str, (size_t)out + 1);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;
    mp_vsnprintf((char*)str->data, str->length, format, args2);
    str->length--;

 errout:
    va_end(args2);
    return res;
}

/* QualifiedName */
UA_Boolean
UA_QualifiedName_isNull(const UA_QualifiedName *q) {
    return (q->namespaceIndex == 0 && q->name.length == 0);
}

UA_QualifiedName
UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars) {
    UA_QualifiedName qn;
    qn.namespaceIndex = nsIndex;
    qn.name = UA_STRING(chars);
    return qn;
}

UA_QualifiedName
UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars) {
    UA_QualifiedName qn;
    qn.namespaceIndex = nsIndex;
    qn.name = UA_STRING_ALLOC(chars);
    return qn;
}

static UA_StatusCode
QualifiedName_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_QualifiedName *srcQ = (const UA_QualifiedName*)src;
    UA_QualifiedName *dstQ = (UA_QualifiedName*)dst;
    dstQ->namespaceIndex = srcQ->namespaceIndex;
    return String_copy(&srcQ->name, &dstQ->name, NULL);
}

static void
QualifiedName_clear(void *p, const UA_DataType *_) {
    UA_QualifiedName *qn = (UA_QualifiedName*)p;
    String_clear(&qn->name, NULL);
}

u32
UA_QualifiedName_hash(const UA_QualifiedName *q) {
    return UA_ByteString_hash(q->namespaceIndex,
                              q->name.data, q->name.length);
}

UA_StatusCode
UA_QualifiedName_printEx(const UA_QualifiedName *qn, UA_String *output,
                         const UA_NamespaceMapping *nsMapping) {
    /* If the QualifiedName is NULL, return a NULL string */
    if(qn->name.data == NULL && qn->namespaceIndex == 0) {
        UA_String_clear(output);
        return UA_STATUSCODE_GOOD;
    }

    /* Start tracking the output length */
    size_t len = qn->name.length;

    /* Try to map the NamespaceIndex to the Uri */
    UA_String nsUri = UA_STRING_NULL;
    if(qn->namespaceIndex > 0 && nsMapping) {
        UA_NamespaceMapping_index2Uri(nsMapping, qn->namespaceIndex, &nsUri);
        if(nsUri.length > 0)
            len += nsUri.length + 1;
    }

    /* Print the NamespaceIndex */
    char nsStr[6];
    size_t nsStrSize = 0;
    if(nsUri.length == 0 && qn->namespaceIndex > 0) {
        nsStrSize = itoaUnsigned(qn->namespaceIndex, nsStr, 10);
        len += 1 + nsStrSize;
    }

    /* Allocate memory if required */
    if(output->length == 0) {
        UA_StatusCode res = UA_ByteString_allocBuffer((UA_ByteString*)output, len);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else {
        if(output->length < len)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        output->length = len;
    }

    /* Print the namespace */
    u8 *pos = output->data;
    if(nsUri.length > 0) {
        memcpy(pos, nsUri.data, nsUri.length);
        pos += nsUri.length;
        *pos++ = ';';
    } else if(qn->namespaceIndex > 0) {
        memcpy(pos, nsStr, nsStrSize);
        pos += nsStrSize;
        *pos++ = ':';
    }

    /* Print the name */
    if(UA_LIKELY(qn->name.data != NULL))
        memcpy(pos, qn->name.data, qn->name.length);

    UA_assert(output->length == (size_t)((UA_Byte*)pos + qn->name.length - output->data));
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_QualifiedName_print(const UA_QualifiedName *qn, UA_String *output) {
    return UA_QualifiedName_printEx(qn, output, NULL);
}

/* DateTime */
UA_Int64
UA_DateTime_toUnixTime(UA_DateTime date) {
    return (date - UA_DATETIME_UNIX_EPOCH) / UA_DATETIME_SEC;
}

UA_DateTime
UA_DateTime_fromUnixTime(UA_Int64 unixDate) {
    return (unixDate * UA_DATETIME_SEC) + UA_DATETIME_UNIX_EPOCH;
}

UA_DateTimeStruct
UA_DateTime_toStruct(UA_DateTime t) {
    /* Divide, then subtract -> avoid underflow. Also, negative numbers are
     * rounded up, not down. */
    long long secSinceUnixEpoch = (long long)(t / UA_DATETIME_SEC)
        - (long long)(UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC);

    /* Negative fractions of a second? Remove one full second from the epoch
     * distance and allow only a positive fraction. */
    UA_DateTime frac = t % UA_DATETIME_SEC;
    if(frac < 0) {
        secSinceUnixEpoch--;
        frac += UA_DATETIME_SEC;
    }

    struct musl_tm ts;
    memset(&ts, 0, sizeof(struct musl_tm));
    musl_secs_to_tm(secSinceUnixEpoch, &ts);

    UA_DateTimeStruct dateTimeStruct;
    dateTimeStruct.year   = (i16)(ts.tm_year + 1900);
    dateTimeStruct.month  = (u16)(ts.tm_mon + 1);
    dateTimeStruct.day    = (u16)ts.tm_mday;
    dateTimeStruct.hour   = (u16)ts.tm_hour;
    dateTimeStruct.min    = (u16)ts.tm_min;
    dateTimeStruct.sec    = (u16)ts.tm_sec;
    dateTimeStruct.milliSec = (u16)((frac % 10000000) / 10000);
    dateTimeStruct.microSec = (u16)((frac % 10000) / 10);
    dateTimeStruct.nanoSec  = (u16)((frac % 10) * 100);
    return dateTimeStruct;
}

UA_DateTime
UA_DateTime_fromStruct(UA_DateTimeStruct ts) {
    /* Seconds since the Unix epoch */
    struct musl_tm tm;
    memset(&tm, 0, sizeof(struct musl_tm));
    tm.tm_year = ts.year - 1900;
    tm.tm_mon = ts.month - 1;
    tm.tm_mday = ts.day;
    tm.tm_hour = ts.hour;
    tm.tm_min = ts.min;
    tm.tm_sec = ts.sec;
    long long sec_epoch = musl_tm_to_secs(&tm);

    UA_DateTime t = UA_DATETIME_UNIX_EPOCH;
    t += sec_epoch * UA_DATETIME_SEC;
    t += ts.milliSec * UA_DATETIME_MSEC;
    t += ts.microSec * UA_DATETIME_USEC;
    t += ts.nanoSec / 100;
    return t;
}

UA_StatusCode
UA_DateTime_parse(UA_DateTime *dst, const UA_String str) {
    if(str.length == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    struct musl_tm dts;
    memset(&dts, 0, sizeof(dts));

    /* Parse the year. The ISO standard asks for four digits. But we accept up
     * to five with an optional plus or minus in front due to the range of the
     * DateTime 64bit integer. But in that case we require the year and the
     * month to be separated by a '-'. Otherwise we cannot know where the month
     * starts. */
    size_t pos = 0;
    if(str.data[0] == '-' || str.data[0] == '+')
        pos++;
    UA_Int64 year = 0;
    UA_CHECK(str.length - pos > 5, return UA_STATUSCODE_BADDECODINGERROR);
    size_t len = parseInt64((char*)&str.data[pos], 5, &year);
    pos += len;
    UA_CHECK(len > 0 && pos < str.length, return UA_STATUSCODE_BADDECODINGERROR);
    UA_CHECK(len == 4 || str.data[pos] == '-', return UA_STATUSCODE_BADDECODINGERROR);
    if(str.data[0] == '-')
        year = -year;
    dts.tm_year = (UA_Int16)year - 1900;
    if(str.data[pos] == '-')
        pos++;

    /* Parse the month */
    UA_UInt64 month = 0;
    UA_CHECK(str.length - pos > 2, return UA_STATUSCODE_BADDECODINGERROR);
    len = parseUInt64((char*)&str.data[pos], 2, &month);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_mon = (UA_UInt16)month - 1;
    if(str.data[pos] == '-')
        pos++;

    /* Parse the day and check the T between date and time */
    UA_UInt64 day = 0;
    UA_CHECK(str.length - pos > 2, return UA_STATUSCODE_BADDECODINGERROR);
    len = parseUInt64((char*)&str.data[pos], 2, &day);
    pos += len;
    UA_CHECK(len == 2 || str.data[pos] != 'T',
             return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_mday = (UA_UInt16)day;
    pos++;

    /* Parse the hour */
    UA_UInt64 hour = 0;
    UA_CHECK(str.length - pos > 2, return UA_STATUSCODE_BADDECODINGERROR);
    len = parseUInt64((char*)&str.data[pos], 2, &hour);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_hour = (UA_UInt16)hour;
    if(str.data[pos] == ':')
        pos++;

    /* Parse the minute */
    UA_UInt64 min = 0;
    UA_CHECK(str.length - pos > 2, return UA_STATUSCODE_BADDECODINGERROR);
    len = parseUInt64((char*)&str.data[pos], 2, &min);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_min = (UA_UInt16)min;
    if(str.data[pos] == ':')
        pos++;

    /* Parse the second */
    UA_UInt64 sec = 0;
    UA_CHECK(str.length - pos >= 2, return UA_STATUSCODE_BADDECODINGERROR);
    len = parseUInt64((char*)&str.data[pos], 2, &sec);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_sec = (UA_UInt16)sec;

    /* Compute the seconds since the Unix epoch */
    long long sinceunix = musl_tm_to_secs(&dts);

    /* Are we within the range that can be represented? */
    long long sinceunix_min =
        (long long)(UA_INT64_MIN / UA_DATETIME_SEC) -
        (long long)(UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC) -
        (long long)1; /* manual correction due to rounding */
    long long sinceunix_max = (long long)
        ((UA_INT64_MAX - UA_DATETIME_UNIX_EPOCH) / UA_DATETIME_SEC);
    if(sinceunix < sinceunix_min || sinceunix > sinceunix_max)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Convert to DateTime. Add or subtract one extra second here to prevent
     * underflow/overflow. This is reverted once the fractional part has been
     * added. */
    sinceunix -= (sinceunix > 0) ? 1 : -1;
    UA_DateTime dt = (UA_DateTime)
        (sinceunix + (UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC)) * UA_DATETIME_SEC;

    /* Parse the fraction of the second if defined */
    UA_CHECK(pos < str.length, goto finish);
    if(str.data[pos] == ',' || str.data[pos] == '.') {
        pos++;
        double frac = 0.0;
        double denom = 0.1;
        while(pos < str.length && str.data[pos] >= '0' && str.data[pos] <= '9') {
            frac += denom * (str.data[pos] - '0');
            denom *= 0.1;
            pos++;
        }
        frac += 0.00000005; /* Correct rounding when converting to integer */
        dt += (UA_DateTime)(frac * UA_DATETIME_SEC);
    }

    /* Time zone handling */
    UA_CHECK(pos < str.length, goto finish);
    if(str.data[pos] == 'Z') {
        pos++;
    } else if(str.data[pos] == '+' || str.data[pos] == '-') {
        UA_UInt64 tzHour = 0, tzMin = 0;
        UA_Int64 offsetSeconds = 0;
        UA_Byte tzSign = str.data[pos++];

        UA_CHECK(str.length - pos >= 2, return UA_STATUSCODE_BADDECODINGERROR);
        len = parseUInt64((char*)&str.data[pos], 2, &tzHour);
        pos += len;
        UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);

        UA_CHECK(str.length > pos, goto finish); /* Allow missing tz minutes */
        if(str.data[pos] == ':')
            pos++;

        UA_CHECK(str.length - pos >= 2, return UA_STATUSCODE_BADDECODINGERROR);
        len = parseUInt64((char*)&str.data[pos], 2, &tzMin);
        pos += len;
        UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);

        offsetSeconds = (tzHour * 3600) + (tzMin * 60);
        if(tzSign == '-')
            offsetSeconds = -offsetSeconds;
        dt -= (UA_DateTime)(offsetSeconds * UA_DATETIME_SEC);
    } else {
        return UA_STATUSCODE_BADDECODINGERROR;
    }

 finish:
    /* Remove the underflow/overflow protection (see above) */
    if(sinceunix > 0) {
        if(dt > UA_INT64_MAX - UA_DATETIME_SEC)
            return UA_STATUSCODE_BADDECODINGERROR;
        dt += UA_DATETIME_SEC;
    } else {
        if(dt < UA_INT64_MIN + UA_DATETIME_SEC)
            return UA_STATUSCODE_BADDECODINGERROR;
        dt -= UA_DATETIME_SEC;
    }

    /* We must be at the end of the string */
    if(pos != str.length)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = dt;
    return UA_STATUSCODE_GOOD;
}

UA_DateTime
UA_DATETIME(const char *chars) {
    UA_DateTime dst;
    UA_StatusCode res =
        UA_DateTime_parse(&dst, UA_STRING((char*)(uintptr_t)chars));
    if(res != UA_STATUSCODE_GOOD)
        UA_DateTime_init(&dst);
    return dst;
}

/* Guid */
static const u8 hexmapLower[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static const u8 hexmapUpper[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

void
UA_Guid_to_hex(const UA_Guid *guid, u8* out, UA_Boolean lower) {
    const u8 *hexmap = (lower) ? hexmapLower : hexmapUpper;
    size_t i = 0, j = 28;
    for(; i<8;i++,j-=4)         /* pos 0-7, 4byte, (a) */
        out[i] = hexmap[(guid->data1 >> j) & 0x0Fu];
    out[i++] = '-';             /* pos 8 */
    for(j=12; i<13;i++,j-=4)    /* pos 9-12, 2byte, (b) */
        out[i] = hexmap[(uint16_t)(guid->data2 >> j) & 0x0Fu];
    out[i++] = '-';             /* pos 13 */
    for(j=12; i<18;i++,j-=4)    /* pos 14-17, 2byte (c) */
        out[i] = hexmap[(uint16_t)(guid->data3 >> j) & 0x0Fu];
    out[i++] = '-';              /* pos 18 */
    for(j=0;i<23;i+=2,j++) {     /* pos 19-22, 2byte (d) */
        out[i] = hexmap[(guid->data4[j] & 0xF0u) >> 4u];
        out[i+1] = hexmap[guid->data4[j] & 0x0Fu];
    }
    out[i++] = '-';              /* pos 23 */
    for(j=2; i<36;i+=2,j++) {    /* pos 24-35, 6byte (e) */
        out[i] = hexmap[(guid->data4[j] & 0xF0u) >> 4u];
        out[i+1] = hexmap[guid->data4[j] & 0x0Fu];
    }
}

UA_StatusCode
UA_Guid_print(const UA_Guid *guid, UA_String *output) {
    if(output->length == 0) {
        UA_StatusCode res =
            UA_ByteString_allocBuffer((UA_ByteString*)output, 36);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else {
        if(output->length < 36)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        output->length = 36;
    }
    UA_Guid_to_hex(guid, output->data, true);
    return UA_STATUSCODE_GOOD;
}

UA_Guid
UA_GUID(const char *chars) {
    UA_Guid guid;
    UA_Guid_parse(&guid, UA_STRING((char*)(uintptr_t)chars));
    return guid;
}

/* ByteString */
UA_StatusCode
UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) {
    UA_ByteString_init(bs);
    if(length == 0) {
        bs->data = (u8*)UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }
    bs->data = (u8*)UA_calloc(1,length);
    if(UA_UNLIKELY(!bs->data))
        return UA_STATUSCODE_BADOUTOFMEMORY;
    bs->length = length;
    return UA_STATUSCODE_GOOD;
}

/* NodeId */
static void
NodeId_clear(void *p, const UA_DataType *_) {
    UA_NodeId *id = (UA_NodeId*)p;
    switch(id->identifierType) {
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        String_clear(&id->identifier.string, NULL);
        break;
    default: break;
    }
}

static UA_StatusCode
NodeId_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_NodeId *srcN = (const UA_NodeId*)src;
    UA_NodeId *dstN = (UA_NodeId *)dst;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(srcN->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        *dstN = *srcN;
        return UA_STATUSCODE_GOOD;
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        retval |= String_copy(&srcN->identifier.string,
                              &dstN->identifier.string, NULL);
        break;
    case UA_NODEIDTYPE_GUID:
        dstN->identifier.guid = srcN->identifier.guid;
        break;
    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    dstN->namespaceIndex = srcN->namespaceIndex;
    dstN->identifierType = srcN->identifierType;
    return retval;
}

UA_Boolean
UA_NodeId_isNull(const UA_NodeId *p) {
    if(p->namespaceIndex != 0)
        return false;
    switch (p->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        return (p->identifier.numeric == 0);
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        return (p->identifier.string.length == 0); /* Null and empty string */
    case UA_NODEIDTYPE_GUID:
        return (guidOrder(&p->identifier.guid, &UA_GUID_NULL, NULL) == UA_ORDER_EQ);
    }
    return false;
}

UA_Order
UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2) {
    return nodeIdOrder(n1, n2, NULL);
}

UA_NodeId
UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier) {
    UA_NodeId id;
    memset(&id, 0, sizeof(UA_NodeId));
    id.namespaceIndex = nsIndex;
    id.identifierType = UA_NODEIDTYPE_NUMERIC;
    id.identifier.numeric = identifier;
    return id;
}

UA_NodeId
UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars) {
    UA_NodeId id;
    memset(&id, 0, sizeof(UA_NodeId));
    id.namespaceIndex = nsIndex;
    id.identifierType = UA_NODEIDTYPE_STRING;
    id.identifier.string = UA_STRING(chars);
    return id;
}

UA_NodeId
UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex,
                       const char *chars) {
    UA_NodeId id;
    memset(&id, 0, sizeof(UA_NodeId));
    id.namespaceIndex = nsIndex;
    id.identifierType = UA_NODEIDTYPE_STRING;
    id.identifier.string = UA_STRING_ALLOC(chars);
    return id;
}

UA_NodeId
UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
    UA_NodeId id;
    memset(&id, 0, sizeof(UA_NodeId));
    id.namespaceIndex = nsIndex;
    id.identifierType = UA_NODEIDTYPE_GUID;
    id.identifier.guid = guid;
    return id;
}

UA_NodeId
UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
    UA_NodeId id;
    memset(&id, 0, sizeof(UA_NodeId));
    id.namespaceIndex = nsIndex;
    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
    id.identifier.byteString = UA_BYTESTRING(chars);
    return id;
}

UA_NodeId
UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex,
                           const char *chars) {
    UA_NodeId id;
    memset(&id, 0, sizeof(UA_NodeId));
    id.namespaceIndex = nsIndex;
    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
    id.identifier.byteString = UA_BYTESTRING_ALLOC(chars);
    return id;
}

/* sdbm-hash (http://www.cse.yorku.ca/~oz/hash.html) */
u32
UA_ByteString_hash(u32 initialHashValue,
                   const u8 *data, size_t size) {
    u32 h = initialHashValue;
    for(size_t i = 0; i < size; i++)
        h = data[i] + (h << 6) + (h << 16) - h;
    return h;
}

u32
UA_NodeId_hash(const UA_NodeId *n) {
    switch(n->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
    default:
        return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.numeric,
                                  sizeof(UA_UInt32));
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        return UA_ByteString_hash(n->namespaceIndex, n->identifier.string.data,
                                  n->identifier.string.length);
    case UA_NODEIDTYPE_GUID:
        return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.guid,
                                  sizeof(UA_Guid));
    }
}

/* Computes length for the encoding size and pre-encodes the numeric values.
 * This can be larger than the actual size due to the removed base64 padding
 * (for the percent-escaping). */
static size_t
nodeIdSize(const UA_NodeId *id, u8 *nsStr, u8 *numIdStr, UA_String nsUri,
           UA_Escaping idEsc) {
    /* Namespace length */
    size_t len = 0;
    if(nsUri.data != NULL) {
        len += 5; /* nsu=; */
        len += UA_String_escapedSize(nsUri, UA_ESCAPING_PERCENT);
    } else if(id->namespaceIndex > 0) {
        len += 4; /* ns=; */
        size_t nsStrSize = itoaUnsigned(id->namespaceIndex, (char*)nsStr, 10);
        nsStr[nsStrSize] = 0;
        len += nsStrSize;
    }

    len += 2; /* ?= */

    switch (id->identifierType) {
    case UA_NODEIDTYPE_NUMERIC: {
        size_t numIdStrSize = itoaUnsigned(id->identifier.numeric, (char*)numIdStr, 10);
        numIdStr[numIdStrSize] = 0;
        len += numIdStrSize;
        break;
    }
    case UA_NODEIDTYPE_STRING:
        len += UA_String_escapedSize(id->identifier.string, idEsc);
        break;
    case UA_NODEIDTYPE_GUID:
        len += 36;
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        len += 4 * ((id->identifier.byteString.length + 2) / 3);
        break;
    default:
        len = 0;
    }
    return len;
}

static u8 *
printNodeIdBody(const UA_NodeId *id, UA_String nsUri, u8* nsStr, u8* numIdStr, u8 *pos,
                const UA_NamespaceMapping *nsMapping, UA_Escaping idEsc) {
    size_t len;

    /* Encode the namespace */
    if(nsUri.data != NULL) {
        memcpy(pos, "nsu=", 4);
        pos += 4;
        pos += UA_String_escapeInsert(pos, nsUri, UA_ESCAPING_PERCENT);
        *pos++ = ';';
    } else if(id->namespaceIndex > 0) {
        memcpy(pos, "ns=", 3);
        pos += 3;
        len = strlen((char*)nsStr);
        memcpy(pos, nsStr, len);
        pos += len;
        *pos++ = ';';
    }

    /* Encode the identifier */
    switch(id->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        memcpy(pos, "i=", 2);
        pos += 2;
        len = strlen((char*)numIdStr);
        memcpy(pos, numIdStr, len);
        pos += len;
        break;
    case UA_NODEIDTYPE_STRING:
        memcpy(pos, "s=", 2);
        pos += 2;
        pos += UA_String_escapeInsert(pos, id->identifier.string, idEsc);
        break;
    case UA_NODEIDTYPE_GUID:
        memcpy(pos, "g=", 2);
        pos += 2;
        UA_Guid_to_hex(&id->identifier.guid, pos, true);
        pos += 36;
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        memcpy(pos, "b=", 2);
        pos += 2;
        /* Use base64url encoding for percent-escaping.
         * Replace +/ with -_ and remove the padding. */
        u8 *bpos = pos;
        pos += UA_base64_buf(id->identifier.byteString.data,
                             id->identifier.byteString.length, pos);
        if(idEsc == UA_ESCAPING_PERCENT ||
           idEsc == UA_ESCAPING_PERCENT_EXTENDED) {
            while(pos > bpos && pos[-1] == '=')
                pos--;
            for(; bpos < pos; bpos++) {
                if(*bpos == '+') *bpos = '-';
                else if(*bpos == '/') *bpos = '_';
            }
        }
        break;
    }
    return pos;
}

UA_StatusCode
nodeId_printEscape(const UA_NodeId *id, UA_String *output,
                   const UA_NamespaceMapping *nsMapping, UA_Escaping idEsc) {
    /* Try to map the NamespaceIndex to the Uri */
    UA_String nsUri = UA_STRING_NULL;
    if(id->namespaceIndex > 0 && nsMapping)
        UA_NamespaceMapping_index2Uri(nsMapping, id->namespaceIndex, &nsUri);

    /* Compute the string length and print numerical identifiers. */
    u8 nsStr[7];
    u8 numIdStr[12];
    size_t idLen = nodeIdSize(id, nsStr, numIdStr, nsUri, idEsc);
    if(idLen == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate memory if required */
    if(output->length == 0) {
        UA_StatusCode res = UA_ByteString_allocBuffer((UA_ByteString*)output, idLen);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else {
        if(output->length < idLen)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        output->length = idLen;
    }

    /* Print the NodeId */
    u8 *pos = printNodeIdBody(id, nsUri, nsStr, numIdStr, output->data, nsMapping, idEsc);
    output->length = (size_t)(pos - output->data);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_NodeId_printEx(const UA_NodeId *id, UA_String *output,
                  const UA_NamespaceMapping *nsMapping) {
    return nodeId_printEscape(id, output, nsMapping, UA_ESCAPING_NONE);
}

UA_StatusCode
UA_NodeId_print(const UA_NodeId *id, UA_String *output) {
    return UA_NodeId_printEx(id, output, NULL);
}

UA_NodeId UA_NODEID(const char *chars) {
    UA_NodeId id;
    UA_NodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars));
    return id;
}

/* ExpandedNodeId */
static void
ExpandedNodeId_clear(void *p, const UA_DataType *_) {
    UA_ExpandedNodeId *id = (UA_ExpandedNodeId*)p;
    NodeId_clear(&id->nodeId, NULL);
    String_clear(&id->namespaceUri, NULL);
}

static UA_StatusCode
ExpandedNodeId_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_ExpandedNodeId *srcE = (const UA_ExpandedNodeId *)src;
    UA_ExpandedNodeId *dstE = (UA_ExpandedNodeId*)dst;
    UA_StatusCode retval = NodeId_copy(&srcE->nodeId, &dstE->nodeId, NULL);
    retval |= String_copy(&srcE->namespaceUri, &dstE->namespaceUri, NULL);
    dstE->serverIndex = srcE->serverIndex;
    return retval;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier) {
    UA_ExpandedNodeId id;
    memset(&id, 0, sizeof(UA_ExpandedNodeId));
    id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier);
    return id;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars) {
    UA_ExpandedNodeId id;
    memset(&id, 0, sizeof(UA_ExpandedNodeId));
    id.nodeId = UA_NODEID_STRING(nsIndex, chars);
    return id;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
    UA_ExpandedNodeId id;
    memset(&id, 0, sizeof(UA_ExpandedNodeId));
    id.nodeId = UA_NODEID_STRING_ALLOC(nsIndex, chars);
    return id;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
    UA_ExpandedNodeId id;
    memset(&id, 0, sizeof(UA_ExpandedNodeId));
    id.nodeId = UA_NODEID_GUID(nsIndex, guid);
    return id;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
    UA_ExpandedNodeId id;
    memset(&id, 0, sizeof(UA_ExpandedNodeId));
    id.nodeId = UA_NODEID_BYTESTRING(nsIndex, chars);
    return id;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
    UA_ExpandedNodeId id;
    memset(&id, 0, sizeof(UA_ExpandedNodeId));
    id.nodeId = UA_NODEID_BYTESTRING_ALLOC(nsIndex, chars);
    return id;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID_NODEID(UA_NodeId nodeId) {
    UA_ExpandedNodeId id;
    memset(&id, 0, sizeof(UA_ExpandedNodeId));
    id.nodeId = nodeId;
    return id;
}

UA_ExpandedNodeId
UA_EXPANDEDNODEID(const char *chars) {
    UA_ExpandedNodeId id;
    UA_ExpandedNodeId_parse(&id, UA_STRING((char*)(uintptr_t)chars));
    return id;
}

UA_Boolean
UA_ExpandedNodeId_isLocal(const UA_ExpandedNodeId *n) {
    return (n->namespaceUri.length == 0 && n->serverIndex == 0);
}

UA_Order
UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1,
                        const UA_ExpandedNodeId *n2) {
    return expandedNodeIdOrder(n1, n2, NULL);
}

u32
UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n) {
    u32 h = UA_NodeId_hash(&n->nodeId);
    if(n->serverIndex != 0)
        h = UA_ByteString_hash(h, (const UA_Byte*)&n->serverIndex, 4);
    if(n->namespaceUri.length != 0)
        h = UA_ByteString_hash(h, n->namespaceUri.data, n->namespaceUri.length);
    return h;
}

UA_StatusCode
UA_ExpandedNodeId_printEx(const UA_ExpandedNodeId *eid, UA_String *output,
                          const UA_NamespaceMapping *nsMapping,
                          size_t serverUrisSize, const UA_String *serverUris) {
    /* Try to map the NamespaceIndex to the Uri */
    UA_String nsUri = eid->namespaceUri;
    if(nsUri.data == NULL && eid->nodeId.namespaceIndex > 0 && nsMapping)
        UA_NamespaceMapping_index2Uri(nsMapping, eid->nodeId.namespaceIndex, &nsUri);

    /* Try to map the ServerIndex to a Uri */
    UA_String srvUri = UA_STRING_NULL;
    if(eid->serverIndex > 0 && eid->serverIndex < serverUrisSize)
        srvUri = serverUris[eid->serverIndex];

    /* No special escaping for ExpandedNodeIds */
    UA_Escaping idEsc = UA_ESCAPING_NONE;

    /* Compute the NodeId string length */
    u8 nsStr[7];
    u8 numIdStr[12];
    char srvIdxStr[11];
    size_t srvIdxSize = 0;
    size_t idLen = nodeIdSize(&eid->nodeId, nsStr, numIdStr, nsUri, idEsc);
    if(idLen == 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(srvUri.length  > 0) {
        idLen += 5; /* svu=; */
        idLen += UA_String_escapedSize(srvUri, UA_ESCAPING_PERCENT);
    } else if(eid->serverIndex > 0) {
        idLen += 5; /* svr=; */
        srvIdxSize = itoaUnsigned(eid->serverIndex, srvIdxStr, 10);
        idLen += srvIdxSize;
    }

    /* Allocate memory if required */
    if(output->length == 0) {
        UA_StatusCode res = UA_ByteString_allocBuffer((UA_ByteString*)output, idLen);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else {
        if(output->length < idLen)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        output->length = idLen;
    }

    /* Encode the ServerIndex or ServerUrl */
    u8 *pos = output->data;
    if(srvUri.length  > 0) {
        memcpy(pos, "svu=", 4);
        pos += 4;
        pos += UA_String_escapeInsert(pos, srvUri, UA_ESCAPING_PERCENT);
        *pos++ = ';';
    } else if(eid->serverIndex > 0) {
        memcpy(pos, "svr=", 4);
        pos += 4;
        memcpy(pos, srvIdxStr, srvIdxSize);
        pos += srvIdxSize;
        *pos++ = ';';
    }

    /* Print the NodeId */
    pos = printNodeIdBody(&eid->nodeId, nsUri, nsStr, numIdStr, pos, nsMapping, idEsc);
    output->length = (size_t)(pos - output->data);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ExpandedNodeId_print(const UA_ExpandedNodeId *eid, UA_String *output) {
    return UA_ExpandedNodeId_printEx(eid, output, NULL, 0, NULL);
}

/* ExtensionObject */
static void
ExtensionObject_clear(void *p, const UA_DataType *_) {
    UA_ExtensionObject *eo = (UA_ExtensionObject *)p;
    switch(eo->encoding) {
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
    case UA_EXTENSIONOBJECT_ENCODED_XML:
        NodeId_clear(&eo->content.encoded.typeId, NULL);
        String_clear(&eo->content.encoded.body, NULL);
        break;
    case UA_EXTENSIONOBJECT_DECODED:
        if(eo->content.decoded.data)
            UA_delete(eo->content.decoded.data, eo->content.decoded.type);
        break;
    default:
        break;
    }
}

static UA_StatusCode
ExtensionObject_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_ExtensionObject *srcE = (const UA_ExtensionObject *)src;
    UA_ExtensionObject *dstE = (UA_ExtensionObject *)dst;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(srcE->encoding) {
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
    case UA_EXTENSIONOBJECT_ENCODED_XML:
        dstE->encoding = srcE->encoding;
        retval = NodeId_copy(&srcE->content.encoded.typeId,
                             &dstE->content.encoded.typeId, NULL);
        /* ByteString -> copy as string */
        retval |= String_copy(&srcE->content.encoded.body,
                              &dstE->content.encoded.body, NULL);
        break;
    case UA_EXTENSIONOBJECT_DECODED:
    case UA_EXTENSIONOBJECT_DECODED_NODELETE:
        if(!srcE->content.decoded.type || !srcE->content.decoded.data)
            return UA_STATUSCODE_BADINTERNALERROR;
        dstE->encoding = UA_EXTENSIONOBJECT_DECODED;
        dstE->content.decoded.type = srcE->content.decoded.type;
        retval = UA_Array_copy(srcE->content.decoded.data, 1,
                               &dstE->content.decoded.data,
                               srcE->content.decoded.type);
        break;
    default:
        break;
    }
    return retval;
}

void
UA_ExtensionObject_setValue(UA_ExtensionObject *eo,
                            void * UA_RESTRICT p,
                            const UA_DataType *type) {
    UA_ExtensionObject_init(eo);
    eo->content.decoded.data = p;
    eo->content.decoded.type = type;
    eo->encoding = UA_EXTENSIONOBJECT_DECODED;
}

void
UA_ExtensionObject_setValueNoDelete(UA_ExtensionObject *eo,
                                    void * UA_RESTRICT p,
                                    const UA_DataType *type) {
    UA_ExtensionObject_init(eo);
    eo->content.decoded.data = p;
    eo->content.decoded.type = type;
    eo->encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
}

UA_StatusCode
UA_ExtensionObject_setValueCopy(UA_ExtensionObject *eo,
                                void * UA_RESTRICT p,
                                const UA_DataType *type) {
    UA_ExtensionObject_init(eo);

    /* Make a copy of the value */
    void *val = UA_malloc(type->memSize);
    if(UA_UNLIKELY(!val))
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_StatusCode res = UA_copy(p, val, type);
    if(UA_UNLIKELY(res != UA_STATUSCODE_GOOD)) {
        UA_free(val);
        return res;
    }

    /* Set the ExtensionObject */
    eo->content.decoded.data = val;
    eo->content.decoded.type = type;
    eo->encoding = UA_EXTENSIONOBJECT_DECODED;
    return UA_STATUSCODE_GOOD;
}

UA_Boolean
UA_ExtensionObject_hasDecodedType(const UA_ExtensionObject *eo,
                                  const UA_DataType *type) {
    if(eo->encoding != UA_EXTENSIONOBJECT_DECODED &&
       eo->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
        return false;
    return (eo->content.decoded.data != NULL &&
            eo->content.decoded.type == type);
}

/* Variant */
UA_Boolean
UA_Variant_isEmpty(const UA_Variant *v) {
    return v->type == NULL;
}

UA_Boolean
UA_Variant_isScalar(const UA_Variant *v) {
    return (v->type != NULL && v->arrayLength == 0 &&
            v->data > UA_EMPTY_ARRAY_SENTINEL);
}

UA_Boolean
UA_Variant_hasScalarType(const UA_Variant *v, const UA_DataType *type) {
    return UA_Variant_isScalar(v) && type == v->type;
}

UA_Boolean
UA_Variant_isArray(const UA_Variant *v) {
    return (v->type != NULL && !UA_Variant_isScalar(v));
}

UA_Boolean
UA_Variant_hasArrayType(const UA_Variant *v, const UA_DataType *type) {
    return (!UA_Variant_isScalar(v)) && type == v->type;
}

static void
Variant_clear(void *p, const UA_DataType *_) {
    UA_Variant *v = (UA_Variant *)p;

    /* The content is "borrowed" */
    if(v->storageType == UA_VARIANT_DATA_NODELETE)
        return;

    /* Delete the value */
    if(v->type && v->data > UA_EMPTY_ARRAY_SENTINEL) {
        if(v->arrayLength == 0)
            v->arrayLength = 1;
        UA_Array_delete(v->data, v->arrayLength, v->type);
        v->data = NULL;
    }

    /* Delete the array dimensions */
    if((void*)v->arrayDimensions > UA_EMPTY_ARRAY_SENTINEL)
        UA_free(v->arrayDimensions);
}

static UA_StatusCode
Variant_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_Variant *srcV = (const UA_Variant *)src;
    UA_Variant *dstV = (UA_Variant *)dst;
    size_t length = srcV->arrayLength;
    if(UA_Variant_isScalar(srcV))
        length = 1;
    UA_StatusCode retval = UA_Array_copy(srcV->data, length,
                                         &dstV->data, srcV->type);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    dstV->arrayLength = srcV->arrayLength;
    dstV->type = srcV->type;
    if(srcV->arrayDimensions) {
        retval = UA_Array_copy(srcV->arrayDimensions, srcV->arrayDimensionsSize,
            (void**)&dstV->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        dstV->arrayDimensionsSize = srcV->arrayDimensionsSize;
    }
    return UA_STATUSCODE_GOOD;
}

void
UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p,
                     const UA_DataType *type) {
    UA_Variant_init(v);
    v->type = type;
    v->arrayLength = 0;
    v->data = p;
}

UA_StatusCode
UA_Variant_setScalarCopy(UA_Variant *v, const void * UA_RESTRICT p,
                         const UA_DataType *type) {
    void *n = UA_malloc(type->memSize);
    if(UA_UNLIKELY(!n))
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_StatusCode retval = UA_copy(p, n, type);
    if(UA_UNLIKELY(retval != UA_STATUSCODE_GOOD)) {
        UA_free(n);
        //cppcheck-suppress memleak
        return retval;
    }
    UA_Variant_setScalar(v, n, type);
    //cppcheck-suppress memleak
    return UA_STATUSCODE_GOOD;
}

void UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array,
                         size_t arraySize, const UA_DataType *type) {
    UA_Variant_init(v);
    v->data = array;
    v->arrayLength = arraySize;
    v->type = type;
}

UA_StatusCode
UA_Variant_setArrayCopy(UA_Variant *v, const void * UA_RESTRICT array,
                        size_t arraySize, const UA_DataType *type) {
    UA_Variant_init(v);
    UA_StatusCode retval = UA_Array_copy(array, arraySize, &v->data, type);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    v->arrayLength = arraySize;
    v->type = type;
    return UA_STATUSCODE_GOOD;
}

/* Test if a range is compatible with a variant. This may adjust the upper bound
 * (max) in order to fit the variant. */
static UA_StatusCode
checkAdjustRange(const UA_Variant *v, UA_NumericRange *range) {
    /* Test for max array size (64bit only) */
#if (SIZE_MAX > 0xffffffff)
    if(v->arrayLength > UA_UINT32_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;
#endif
    u32 arrayLength = (u32)v->arrayLength;

    /* Assume one array dimension if none defined */
    const u32 *dims = v->arrayDimensions;
    size_t dims_count = v->arrayDimensionsSize;
    if(v->arrayDimensionsSize == 0) {
        dims_count = 1;
        dims = &arrayLength;
    }

    /* Does the range match the dimension of the variant? */
    if(range->dimensionsSize != dims_count)
        return UA_STATUSCODE_BADINDEXRANGENODATA;

    /* Check that the number of elements in the variant matches the array
     * dimensions */
    size_t elements = 1;
    for(size_t i = 0; i < dims_count; ++i)
        elements *= dims[i];
    if(elements != v->arrayLength)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Test the integrity of the range and compute the max index used for every
     * dimension. The standard says in Part 4, Section 7.22:
     *
     * When reading a value, the indexes may not specify a range that is within
     * the bounds of the array. The Server shall return a partial result if some
     * elements exist within the range. */
    for(size_t i = 0; i < dims_count; ++i) {
        if(range->dimensions[i].min > range->dimensions[i].max)
            return UA_STATUSCODE_BADINDEXRANGEINVALID;
        if(range->dimensions[i].min >= dims[i])
            return UA_STATUSCODE_BADINDEXRANGENODATA;

        /* Reduce the max to fit the variant */
        if(range->dimensions[i].max >= dims[i])
            range->dimensions[i].max = dims[i] - 1;
    }

    return UA_STATUSCODE_GOOD;
}

/* Computes the stride for copying the range elements.
 * - total: how many elements are in the range
 * - block: how big is each contiguous block of elements in the variant that
 *   maps into the range
 * - stride: how many elements are between the blocks (beginning to beginning)
 * - first: where does the first block begin */
static void
computeStrides(const UA_Variant *v, const UA_NumericRange range,
               size_t *total, size_t *block, size_t *stride, size_t *first) {
    /* Number of total elements to be copied */
    size_t count = 1;
    for(size_t i = 0; i < range.dimensionsSize; ++i)
        count *= (range.dimensions[i].max - range.dimensions[i].min) + 1;
    *total = count;

    /* Assume one array dimension if none defined */
    u32 arrayLength = (u32)v->arrayLength;
    const u32 *dims = v->arrayDimensions;
    size_t dims_count = v->arrayDimensionsSize;
    if(v->arrayDimensionsSize == 0) {
        dims_count = 1;
        dims = &arrayLength;
    }

    /* Compute the stride length and the position of the first element */
    *block = count;           /* Assume the range describes the entire array. */
    *stride = v->arrayLength; /* So it can be copied as a contiguous block.   */
    *first = 0;
    size_t running_dimssize = 1;
    UA_Boolean found_contiguous = false;
    for(size_t k = dims_count; k > 0;) {
        --k;
        size_t dimrange = 1 + range.dimensions[k].max - range.dimensions[k].min;
        if(!found_contiguous && dimrange != dims[k]) {
            /* Found the maximum block that can be copied contiguously */
            found_contiguous = true;
            *block = running_dimssize * dimrange;
            *stride = running_dimssize * dims[k];
        }
        *first += running_dimssize * range.dimensions[k].min;
        running_dimssize *= dims[k];
    }
}

/* Is the type string-like? */
static UA_Boolean
isStringLike(const UA_DataType *type) {
    if(type == &UA_TYPES[UA_TYPES_STRING] ||
       type == &UA_TYPES[UA_TYPES_BYTESTRING] ||
       type == &UA_TYPES[UA_TYPES_XMLELEMENT])
        return true;
    return false;
}

/* Returns the part of the string that lies within the rangedimension */
static UA_StatusCode
copySubString(const UA_String *src, UA_String *dst,
              const UA_NumericRangeDimension *dim) {
    if(dim->min > dim->max)
        return UA_STATUSCODE_BADINDEXRANGEINVALID;
    if(dim->min >= src->length)
        return UA_STATUSCODE_BADINDEXRANGENODATA;

    size_t length;
    if(dim->max < src->length)
       length = dim->max - dim->min + 1;
    else
        length = src->length - dim->min;

    UA_StatusCode retval = UA_ByteString_allocBuffer(dst, length);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    memcpy(dst->data, &src->data[dim->min], length);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Variant_copyRange(const UA_Variant *src, UA_Variant * UA_RESTRICT dst,
                     const UA_NumericRange range) {
    if(!src->type)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_Boolean isScalar = UA_Variant_isScalar(src);
    UA_Boolean stringLike = isStringLike(src->type);

    /* Upper bound of the dimensions for stack-allocation */
    if(range.dimensionsSize > UA_MAX_ARRAY_DIMS)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy the const range to a mutable stack location */
    UA_NumericRangeDimension thisrangedims[UA_MAX_ARRAY_DIMS];
    memcpy(thisrangedims, range.dimensions, sizeof(UA_NumericRangeDimension) * range.dimensionsSize);
    UA_NumericRange thisrange = {range.dimensionsSize, thisrangedims};

    UA_NumericRangeDimension scalarThisDimension = {0,0}; /* a single entry */
    UA_NumericRange nextrange = {0, NULL};

    /* Extract the range for copying at this level. The remaining range is dealt
     * with in the "scalar" type that may define an array by itself (string,
     * variant, ...). */
    UA_Variant arraySrc;
    if(isScalar) {
        /* Replace scalar src with array of length 1 */
        arraySrc = *src;
        arraySrc.arrayLength = 1;
        src = &arraySrc;
        /* Deal with all range dimensions within the scalar */
        thisrange.dimensions = &scalarThisDimension;
        thisrange.dimensionsSize = 1;
        nextrange = range;
    } else {
        /* Deal with as many range dimensions as possible right now */
        size_t dims = src->arrayDimensionsSize;
        if(dims == 0)
            dims = 1;
        if(dims > range.dimensionsSize)
            return UA_STATUSCODE_BADINDEXRANGEINVALID;
       thisrange.dimensionsSize = dims;
       nextrange.dimensions = &range.dimensions[dims];
       nextrange.dimensionsSize = range.dimensionsSize - dims;
    }

    UA_StatusCode retval = checkAdjustRange(src, &thisrange);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Compute the strides */
    size_t count, block, stride, first;
    computeStrides(src, thisrange, &count, &block, &stride, &first);
    UA_assert(block > 0);

    /* Allocate the array */
    UA_Variant_init(dst);
    dst->data = UA_Array_new(count, src->type);
    if(!dst->data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Copy the range */
    size_t block_count = count / block;
    size_t elem_size = src->type->memSize;
    uintptr_t nextdst = (uintptr_t)dst->data;
    uintptr_t nextsrc = (uintptr_t)src->data + (elem_size * first);
    if(nextrange.dimensionsSize == 0) {
        /* no nextrange */
        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;
                nextsrc += stride * elem_size;
            }
        } else {
            for(size_t i = 0; i < block_count; ++i) {
                for(size_t j = 0; j < block; ++j) {
                    retval = UA_copy((const void*)nextsrc,
                                     (void*)nextdst, src->type);
                    nextdst += elem_size;
                    nextsrc += elem_size;
                }
                nextsrc += (stride - block) * elem_size;
            }
        }
    } else {
        /* nextrange can only be used for variants and stringlike with remaining
         * range of dimension 1 */
        if(src->type != &UA_TYPES[UA_TYPES_VARIANT]) {
            if(!stringLike)
                retval = UA_STATUSCODE_BADINDEXRANGENODATA;
            if(nextrange.dimensionsSize != 1)
                retval = UA_STATUSCODE_BADINDEXRANGENODATA;
        }

        /* Copy the content */
        for(size_t i = 0; i < block_count; ++i) {
            for(size_t j = 0; j < block && retval == UA_STATUSCODE_GOOD; ++j) {
                if(stringLike)
                    retval = copySubString((const UA_String*)nextsrc,
                                           (UA_String*)nextdst,
                                           nextrange.dimensions);
                else
                    retval = UA_Variant_copyRange((const UA_Variant*)nextsrc,
                                                  (UA_Variant*)nextdst,
                                                  nextrange);
                nextdst += elem_size;
                nextsrc += elem_size;
            }
            nextsrc += (stride - block) * elem_size;
        }
    }

    /* Clean up if copying failed */
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Array_delete(dst->data, count, src->type);
        dst->data = NULL;
        return retval;
    }

    /* Done if scalar */
    dst->type = src->type;
    if(isScalar)
        return retval;

    /* Copy array dimensions */
    dst->arrayLength = count;
    if(src->arrayDimensionsSize > 0) {
        dst->arrayDimensions =
            (u32*)UA_Array_new(thisrange.dimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
        if(!dst->arrayDimensions) {
            Variant_clear(dst, NULL);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        dst->arrayDimensionsSize = thisrange.dimensionsSize;
        for(size_t k = 0; k < thisrange.dimensionsSize; ++k)
            dst->arrayDimensions[k] =
                thisrange.dimensions[k].max - thisrange.dimensions[k].min + 1;
    }
    return UA_STATUSCODE_GOOD;
}

/* TODO: Allow ranges to reach inside a scalars that are array-like, e.g.
 * variant and strings. This is already possible for reading... */
static UA_StatusCode
Variant_setRange(UA_Variant *v, void *array, size_t arraySize,
                 const UA_NumericRange range, UA_Boolean copy) {
    if(!v->type)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Upper bound of the dimensions for stack-allocation */
    if(range.dimensionsSize > UA_MAX_ARRAY_DIMS)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy the const range to a mutable stack location */
    UA_NumericRangeDimension thisrangedims[UA_MAX_ARRAY_DIMS];
    memcpy(thisrangedims, range.dimensions, sizeof(UA_NumericRangeDimension) * range.dimensionsSize);
    UA_NumericRange thisrange = {range.dimensionsSize, thisrangedims};

    UA_StatusCode retval = checkAdjustRange(v, &thisrange);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Compute the strides */
    size_t count, block, stride, first;
    computeStrides(v, range, &count, &block, &stride, &first);
    if(count != arraySize)
        return UA_STATUSCODE_BADINDEXRANGEINVALID;

    /* Move/copy the elements */
    size_t block_count = count / block;
    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->pointerFree || !copy) {
        for(size_t i = 0; i < block_count; ++i) {
            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block);
            nextsrc += block * elem_size;
            nextdst += stride * elem_size;
        }
    } else {
        for(size_t i = 0; i < block_count; ++i) {
            for(size_t j = 0; j < block; ++j) {
                clearJumpTable[v->type->typeKind]((void*)nextdst, v->type);
                retval |= UA_copy((void*)nextsrc, (void*)nextdst, v->type);
                nextdst += elem_size;
                nextsrc += elem_size;
            }
            nextdst += (stride - block) * elem_size;
        }
    }

    /* If members were moved, initialize original array to prevent reuse */
    if(!copy && !v->type->pointerFree)
        memset(array, 0, sizeof(elem_size)*arraySize);

    return retval;
}

UA_StatusCode
UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array,
                    size_t arraySize, const UA_NumericRange range) {
    return Variant_setRange(v, array, arraySize, range, false);
}

UA_StatusCode
UA_Variant_setRangeCopy(UA_Variant *v, const void * UA_RESTRICT array,
                        size_t arraySize, const UA_NumericRange range) {
    return Variant_setRange(v, (void*)(uintptr_t)array,
                            arraySize, range, true);
}

/* LocalizedText */
UA_LocalizedText
UA_LOCALIZEDTEXT(char *locale, char *text) {
    UA_LocalizedText lt;
    lt.locale = UA_STRING(locale);
    lt.text = UA_STRING(text);
    return lt;
}

UA_LocalizedText
UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text) {
    UA_LocalizedText lt;
    lt.locale = UA_STRING_ALLOC(locale);
    lt.text = UA_STRING_ALLOC(text);
    return lt;
}

static void
LocalizedText_clear(void *p, const UA_DataType *_) {
    UA_LocalizedText *lt = (UA_LocalizedText *)p;
    String_clear(&lt->locale, NULL);
    String_clear(&lt->text, NULL);
}

static UA_StatusCode
LocalizedText_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_LocalizedText *srcL = (const UA_LocalizedText *)src;
    UA_LocalizedText *dstL = (UA_LocalizedText *)dst;
    UA_StatusCode retval = String_copy(&srcL->locale, &dstL->locale, NULL);
    retval |= String_copy(&srcL->text, &dstL->text, NULL);
    return retval;
}

/* DataValue */
static void
DataValue_clear(void *p, const UA_DataType *_) {
    UA_DataValue *dv = (UA_DataValue *)p;
    Variant_clear(&dv->value, NULL);
}

static UA_StatusCode
DataValue_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_DataValue *srcD = (const UA_DataValue*)src;
    UA_DataValue *dstD = (UA_DataValue *)dst;
    memcpy(dstD, srcD, sizeof(UA_DataValue));
    UA_Variant_init(&dstD->value);
    UA_StatusCode retval = Variant_copy(&srcD->value, &dstD->value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        DataValue_clear(dstD, NULL);
    return retval;
}

UA_StatusCode
UA_DataValue_copyRange(const UA_DataValue *src, UA_DataValue * UA_RESTRICT dst,
                       const UA_NumericRange range) {
    memcpy(dst, src, sizeof(UA_DataValue));
    UA_Variant_init(&dst->value);
    UA_StatusCode retval = UA_Variant_copyRange(&src->value, &dst->value, range);
    if(retval != UA_STATUSCODE_GOOD)
        DataValue_clear(dst, NULL);
    return retval;
}

/* DiagnosticInfo */
static void
DiagnosticInfo_clear(void *p, const UA_DataType *_) {
    UA_DiagnosticInfo *di = (UA_DiagnosticInfo *)p;

    String_clear(&di->additionalInfo, NULL);
    if(di->hasInnerDiagnosticInfo && di->innerDiagnosticInfo) {
        DiagnosticInfo_clear(di->innerDiagnosticInfo, NULL);
        UA_free(di->innerDiagnosticInfo);
    }
}

static UA_StatusCode
DiagnosticInfo_copy(const void *src, void *dst, const UA_DataType *_) {
    const UA_DiagnosticInfo *srcD = (const UA_DiagnosticInfo *)src;
    UA_DiagnosticInfo *dstD = (UA_DiagnosticInfo *)dst;
    memcpy(dstD, srcD, sizeof(UA_DiagnosticInfo));
    UA_String_init(&dstD->additionalInfo);
    dstD->innerDiagnosticInfo = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(srcD->hasAdditionalInfo)
        retval = String_copy(&srcD->additionalInfo, &dstD->additionalInfo, NULL);
    if(srcD->hasInnerDiagnosticInfo && srcD->innerDiagnosticInfo) {
        dstD->innerDiagnosticInfo = (UA_DiagnosticInfo*)
            UA_malloc(sizeof(UA_DiagnosticInfo));
        if(UA_LIKELY(dstD->innerDiagnosticInfo != NULL)) {
            retval |= DiagnosticInfo_copy(srcD->innerDiagnosticInfo,
                                          dstD->innerDiagnosticInfo, NULL);
            dstD->hasInnerDiagnosticInfo = true;
        } else {
            dstD->hasInnerDiagnosticInfo = false;
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
        }
    }
    return retval;
}

/********************/
/* Structured Types */
/********************/

void *
UA_new(const UA_DataType *type) {
    void *p = UA_calloc(1, type->memSize);
    return p;
}

void UA_init(void *p, const UA_DataType *type) {
    memset(p, 0, type->memSize);
}

static UA_StatusCode
copyByte(const void *src, void *dst, const UA_DataType *_) {
    const u8 *src8 = (const u8 *)src;
    u8 *dst8 = (u8 *)dst;
    *dst8 = *src8;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copy2Byte(const void *src, void *dst, const UA_DataType *_) {
    const u16 *src16 = (const u16 *)src;
    u16 *dst16 = (u16 *)dst;
    *dst16 = *src16;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copy4Byte(const void *src, void *dst, const UA_DataType *_) {
    const u32 *src32 = (const u32 *)src;
    u32 *dst32 = (u32 *)dst;
    *dst32 = *src32;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copy8Byte(const void *src, void *dst, const UA_DataType *_) {
    const u64 *src64 = (const u64 *)src;
    u64 *dst64 = (u64 *)dst;
    *dst64 = *src64;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyGuid(const void *src, void *dst, const UA_DataType *_) {
    const UA_Guid *srcG = (const UA_Guid*)src;
    UA_Guid *dstG = (UA_Guid*)dst;
    *dstG = *srcG;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyStructure(const void *src, void *dst, const UA_DataType *type) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    uintptr_t ptrs = (uintptr_t)src;
    uintptr_t ptrd = (uintptr_t)dst;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptrs += m->padding;
        ptrd += m->padding;
        if(!m->isOptional) {
            if(!m->isArray) {
                retval |= copyJumpTable[mt->typeKind]((const void *)ptrs, (void *)ptrd, mt);
                ptrs += mt->memSize;
                ptrd += mt->memSize;
            } else {
                size_t *dst_size = (size_t*)ptrd;
                const size_t size = *((const size_t*)ptrs);
                ptrs += sizeof(size_t);
                ptrd += sizeof(size_t);
                retval |= UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt);
                if(retval == UA_STATUSCODE_GOOD)
                    *dst_size = size;
                else
                    *dst_size = 0;
                ptrs += sizeof(void*);
                ptrd += sizeof(void*);
            }
        } else {
            if(!m->isArray) {
                if(*(void* const*)ptrs != NULL)
                    retval |= UA_Array_copy(*(void* const*)ptrs, 1, (void**)ptrd, mt);
            } else {
                if(*(void* const*)(ptrs+sizeof(size_t)) != NULL) {
                    size_t *dst_size = (size_t*)ptrd;
                    const size_t size = *((const size_t*)ptrs);
                    ptrs += sizeof(size_t);
                    ptrd += sizeof(size_t);
                    retval |= UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt);
                    if(retval == UA_STATUSCODE_GOOD)
                        *dst_size = size;
                    else
                        *dst_size = 0;
                } else {
                    ptrs += sizeof(size_t);
                    ptrd += sizeof(size_t);
                }
            }
            ptrs += sizeof(void*);
            ptrd += sizeof(void*);
        }
    }
    return retval;
}

static UA_StatusCode
copyUnion(const void *src, void *dst, const UA_DataType *type) {
    uintptr_t ptrs = (uintptr_t) src;
    uintptr_t ptrd = (uintptr_t) dst;
    UA_UInt32 selection = *(UA_UInt32 *)ptrs;
    UA_copy((const UA_UInt32 *) ptrs, (UA_UInt32 *) ptrd, &UA_TYPES[UA_TYPES_UINT32]);
    if(selection == 0)
        return UA_STATUSCODE_GOOD;
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;
    ptrs += m->padding;
    ptrd += m->padding;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    if (m->isArray) {
        size_t *dst_size = (size_t*)ptrd;
        const size_t size = *((const size_t*)ptrs);
        ptrs += sizeof(size_t);
        ptrd += sizeof(size_t);
        retval = UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt);
        if(retval == UA_STATUSCODE_GOOD)
            *dst_size = size;
        else
            *dst_size = 0;
    } else {
        retval = copyJumpTable[mt->typeKind]((const void *)ptrs, (void *)ptrd, mt);
    }

    return retval;
}

static UA_StatusCode
copyNotImplemented(const void *src, void *dst, const UA_DataType *type) {
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const UA_copySignature copyJumpTable[UA_DATATYPEKINDS] = {
    copyByte, /* Boolean */
    copyByte, /* SByte */
    copyByte, /* Byte */
    copy2Byte, /* Int16 */
    copy2Byte, /* UInt16 */
    copy4Byte, /* Int32 */
    copy4Byte, /* UInt32 */
    copy8Byte, /* Int64 */
    copy8Byte, /* UInt64 */
    copy4Byte, /* Float */
    copy8Byte, /* Double */
    String_copy,
    copy8Byte, /* DateTime */
    copyGuid, /* Guid */
    String_copy, /* ByteString */
    String_copy, /* XmlElement */
    NodeId_copy,
    ExpandedNodeId_copy,
    copy4Byte, /* StatusCode */
    QualifiedName_copy,
    LocalizedText_copy,
    ExtensionObject_copy,
    DataValue_copy,
    Variant_copy,
    DiagnosticInfo_copy,
    copyNotImplemented, /* Decimal */
    copy4Byte, /* Enumeration */
    copyStructure,
    copyStructure, /* Structure with Optional Fields */
    copyUnion, /* Union */
    copyNotImplemented /* BitfieldCluster*/
};

UA_StatusCode
UA_copy(const void *src, void *dst, const UA_DataType *type) {
    memset(dst, 0, type->memSize); /* init */
    UA_StatusCode retval = copyJumpTable[type->typeKind](src, dst, type);
    if(retval != UA_STATUSCODE_GOOD)
        UA_clear(dst, type);
    return retval;
}

static void
clearStructure(void *p, const UA_DataType *type) {
    uintptr_t ptr = (uintptr_t)p;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;
        if(!m->isOptional) {
            if(!m->isArray) {
                clearJumpTable[mt->typeKind]((void*)ptr, mt);
                ptr += mt->memSize;
            } else {
                size_t length = *(size_t*)ptr;
                ptr += sizeof(size_t);
                UA_Array_delete(*(void**)ptr, length, mt);
                ptr += sizeof(void*);
            }
        } else { /* field is optional */
            if(!m->isArray) {
                /* optional scalar field is contained */
                if((*(void *const *)ptr != NULL))
                    UA_Array_delete(*(void **)ptr, 1, mt);
                ptr += sizeof(void *);
            } else {
                /* optional array field is contained */
                if((*(void *const *)(ptr + sizeof(size_t)) != NULL)) {
                    size_t length = *(size_t *)ptr;
                    ptr += sizeof(size_t);
                    UA_Array_delete(*(void **)ptr, length, mt);
                    ptr += sizeof(void *);
                } else { /* optional array field not contained */
                    ptr += sizeof(size_t);
                    ptr += sizeof(void *);
                }
            }
        }
    }
}

static void
clearUnion(void *p, const UA_DataType *type) {
    uintptr_t ptr = (uintptr_t) p;
    UA_UInt32 selection = *(UA_UInt32 *)ptr;
    if(selection == 0)
        return;
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;
    ptr += m->padding;
    if (m->isArray) {
        size_t length = *(size_t *)ptr;
        ptr += sizeof(size_t);
        UA_Array_delete(*(void **)ptr, length, mt);
    } else {
        UA_clear((void *) ptr, mt);
    }
}

static void nopClear(void *p, const UA_DataType *type) { }

const
UA_clearSignature clearJumpTable[UA_DATATYPEKINDS] = {
    nopClear, /* Boolean */
    nopClear, /* SByte */
    nopClear, /* Byte */
    nopClear, /* Int16 */
    nopClear, /* UInt16 */
    nopClear, /* Int32 */
    nopClear, /* UInt32 */
    nopClear, /* Int64 */
    nopClear, /* UInt64 */
    nopClear, /* Float */
    nopClear, /* Double */
    String_clear, /* String */
    nopClear, /* DateTime */
    nopClear, /* Guid */
    String_clear, /* ByteString */
    String_clear, /* XmlElement */
    NodeId_clear,
    ExpandedNodeId_clear,
    nopClear, /* StatusCode */
    QualifiedName_clear,
    LocalizedText_clear,
    ExtensionObject_clear,
    DataValue_clear,
    Variant_clear,
    DiagnosticInfo_clear,
    nopClear, /* Decimal, not implemented */
    nopClear, /* Enumeration */
    clearStructure,
    clearStructure, /* Struct with Optional Fields*/
    clearUnion, /* Union*/
    nopClear /* BitfieldCluster, not implemented*/
};

void
UA_clear(void *p, const UA_DataType *type) {
    clearJumpTable[type->typeKind](p, type);
    memset(p, 0, type->memSize); /* init */
}

void
UA_delete(void *p, const UA_DataType *type) {
    clearJumpTable[type->typeKind](p, type);
    UA_free(p);
}

/******************/
/* Value Ordering */
/******************/

#define UA_NUMERICORDER(NAME, TYPE)                                 \
    static UA_Order                                                 \
    NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \
        if(*p1 != *p2)                                              \
            return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE;     \
        return UA_ORDER_EQ;                                         \
    }

UA_NUMERICORDER(booleanOrder, UA_Boolean)
UA_NUMERICORDER(sByteOrder, UA_SByte)
UA_NUMERICORDER(byteOrder, UA_Byte)
UA_NUMERICORDER(int16Order, UA_Int16)
UA_NUMERICORDER(uInt16Order, UA_UInt16)
UA_NUMERICORDER(int32Order, UA_Int32)
UA_NUMERICORDER(uInt32Order, UA_UInt32)
UA_NUMERICORDER(int64Order, UA_Int64)
UA_NUMERICORDER(uInt64Order, UA_UInt64)

#define UA_FLOATORDER(NAME, TYPE)                                   \
    static UA_Order                                                 \
    NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \
        if(*p1 != *p2) {                                            \
            /* p1 is NaN */                                         \
            if(*p1 != *p1) {                                        \
                if(*p2 != *p2)                                      \
                    return UA_ORDER_EQ;                             \
                return UA_ORDER_LESS;                               \
            }                                                       \
            /* p2 is NaN */                                         \
            if(*p2 != *p2)                                          \
                return UA_ORDER_MORE;                               \
            return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE;     \
        }                                                           \
        return UA_ORDER_EQ;                                         \
    }

UA_FLOATORDER(floatOrder, UA_Float)
UA_FLOATORDER(doubleOrder, UA_Double)

static UA_Order
guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *type) {
    if(p1->data1 != p2->data1)
        return (p1->data1 < p2->data1) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->data2 != p2->data2)
        return (p1->data2 < p2->data2) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->data3 != p2->data3)
        return (p1->data3 < p2->data3) ? UA_ORDER_LESS : UA_ORDER_MORE;
    int cmp = memcmp(p1->data4, p2->data4, 8);
    if(cmp != 0)
        return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return UA_ORDER_EQ;
}

static UA_Order
stringOrder(const UA_String *p1, const UA_String *p2, const UA_DataType *type) {
    if(p1->length != p2->length)
        return (p1->length < p2->length) ? UA_ORDER_LESS : UA_ORDER_MORE;
    /* For zero-length arrays, every pointer not NULL is considered a
     * UA_EMPTY_ARRAY_SENTINEL. */
    if(p1->data == p2->data) return UA_ORDER_EQ;
    if(p1->data == NULL) return UA_ORDER_LESS;
    if(p2->data == NULL) return UA_ORDER_MORE;
    int cmp = memcmp((const char*)p1->data, (const char*)p2->data, p1->length);
    if(cmp != 0)
        return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return UA_ORDER_EQ;
}

static UA_Order
nodeIdOrder(const UA_NodeId *p1, const UA_NodeId *p2, const UA_DataType *_) {
    /* Compare namespaceIndex */
    if(p1->namespaceIndex != p2->namespaceIndex)
        return (p1->namespaceIndex < p2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* Compare identifierType */
    if(p1->identifierType != p2->identifierType)
        return (p1->identifierType < p2->identifierType) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* Compare the identifier */
    switch(p1->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
    default:
        if(p1->identifier.numeric != p2->identifier.numeric)
            return (p1->identifier.numeric < p2->identifier.numeric) ?
                UA_ORDER_LESS : UA_ORDER_MORE;
        return UA_ORDER_EQ;
    case UA_NODEIDTYPE_GUID:
        return guidOrder(&p1->identifier.guid, &p2->identifier.guid, NULL);
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        return stringOrder(&p1->identifier.string, &p2->identifier.string, NULL);
    }
}

static UA_Order
expandedNodeIdOrder(const UA_ExpandedNodeId *p1, const UA_ExpandedNodeId *p2,
                    const UA_DataType *_) {
    if(p1->serverIndex != p2->serverIndex)
        return (p1->serverIndex < p2->serverIndex) ? UA_ORDER_LESS : UA_ORDER_MORE;
    UA_Order o = stringOrder(&p1->namespaceUri, &p2->namespaceUri, NULL);
    if(o != UA_ORDER_EQ)
        return o;
    return nodeIdOrder(&p1->nodeId, &p2->nodeId, NULL);
}

static UA_Order
qualifiedNameOrder(const UA_QualifiedName *p1, const UA_QualifiedName *p2,
                   const UA_DataType *_) {
    if(p1->namespaceIndex != p2->namespaceIndex)
        return (p1->namespaceIndex < p2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return stringOrder(&p1->name, &p2->name, NULL);
}

static UA_Order
localizedTextOrder(const UA_LocalizedText *p1, const UA_LocalizedText *p2,
                   const UA_DataType *_) {
    UA_Order o = stringOrder(&p1->locale, &p2->locale, NULL);
    if(o != UA_ORDER_EQ)
        return o;
    return stringOrder(&p1->text, &p2->text, NULL);
}

static UA_Order
extensionObjectOrder(const UA_ExtensionObject *p1, const UA_ExtensionObject *p2,
                     const UA_DataType *_) {
    UA_ExtensionObjectEncoding enc1 = p1->encoding;
    UA_ExtensionObjectEncoding enc2 = p2->encoding;
    if(enc1 > UA_EXTENSIONOBJECT_DECODED)
        enc1 = UA_EXTENSIONOBJECT_DECODED;
    if(enc2 > UA_EXTENSIONOBJECT_DECODED)
        enc2 = UA_EXTENSIONOBJECT_DECODED;
    if(enc1 != enc2)
        return (enc1 < enc2) ? UA_ORDER_LESS : UA_ORDER_MORE;

    switch(enc1) {
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
        return UA_ORDER_EQ;

    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
    case UA_EXTENSIONOBJECT_ENCODED_XML: {
            UA_Order o = nodeIdOrder(&p1->content.encoded.typeId,
                                     &p2->content.encoded.typeId, NULL);
            if(o != UA_ORDER_EQ)
                return o;
            return stringOrder((const UA_String*)&p1->content.encoded.body,
                               (const UA_String*)&p2->content.encoded.body, NULL);
        }

    case UA_EXTENSIONOBJECT_DECODED:
    default: {
            const UA_DataType *type1 = p1->content.decoded.type;
            const UA_DataType *type2 = p2->content.decoded.type;
            if(type1 != type2)
                return ((uintptr_t)type1 < (uintptr_t)type2) ? UA_ORDER_LESS : UA_ORDER_MORE;
            if(!type1)
                return UA_ORDER_EQ;
            return orderJumpTable[type1->typeKind]
                (p1->content.decoded.data, p2->content.decoded.data, type1);
        }
    }
}

/* Part 4: When testing for equality, a Server shall treat null and empty arrays
 * as equal.
 *
 * Don't compare overlayable types as "binary blobs". We have specific order
 * rules also for some overlayable types. For example how NaN floats are
 * compared. */
static UA_Order
arrayOrder(const void *p1, size_t p1Length,
           const void *p2, size_t p2Length,
           const UA_DataType *type) {
    if(p1Length != p2Length)
        return (p1Length < p2Length) ? UA_ORDER_LESS : UA_ORDER_MORE;
    uintptr_t u1 = (uintptr_t)p1;
    uintptr_t u2 = (uintptr_t)p2;
    for(size_t i = 0; i < p1Length; i++) {
        UA_Order o = orderJumpTable[type->typeKind]((const void*)u1, (const void*)u2, type);
        if(o != UA_ORDER_EQ)
            return o;
        u1 += type->memSize;
        u2 += type->memSize;
    }
    return UA_ORDER_EQ;
}

static UA_Order
variantOrder(const UA_Variant *p1, const UA_Variant *p2, const UA_DataType *_) {
    if(p1->type != p2->type)
        return ((uintptr_t)p1->type < (uintptr_t)p2->type) ? UA_ORDER_LESS : UA_ORDER_MORE;

    UA_Order o;
    if(p1->type != NULL) {
        /* Check if both variants are scalars or arrays */
        UA_Boolean s1 = UA_Variant_isScalar(p1);
        UA_Boolean s2 = UA_Variant_isScalar(p2);
        if(s1 != s2)
            return s1 ? UA_ORDER_LESS : UA_ORDER_MORE;
        if(s1) {
            o = orderJumpTable[p1->type->typeKind](p1->data, p2->data, p1->type);
        } else {
            /* Mismatching array length? */
            if(p1->arrayLength != p2->arrayLength)
                return (p1->arrayLength < p2->arrayLength) ? UA_ORDER_LESS : UA_ORDER_MORE;
            o = arrayOrder(p1->data, p1->arrayLength, p2->data, p2->arrayLength, p1->type);
        }
        if(o != UA_ORDER_EQ)
            return o;
    }

    if(p1->arrayDimensionsSize != p2->arrayDimensionsSize)
        return (p1->arrayDimensionsSize < p2->arrayDimensionsSize) ?
            UA_ORDER_LESS : UA_ORDER_MORE;
    o = UA_ORDER_EQ;
    if(p1->arrayDimensionsSize > 0)
        o = arrayOrder(p1->arrayDimensions, p1->arrayDimensionsSize,
                       p2->arrayDimensions, p2->arrayDimensionsSize,
                       &UA_TYPES[UA_TYPES_UINT32]);
    return o;
}

static UA_Order
dataValueOrder(const UA_DataValue *p1, const UA_DataValue *p2, const UA_DataType *_) {
    /* Value */
    if(p1->hasValue != p2->hasValue)
        return (!p1->hasValue) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasValue) {
        UA_Order o = variantOrder(&p1->value, &p2->value, NULL);
        if(o != UA_ORDER_EQ)
            return o;
    }

    /* Status */
    if(p1->hasStatus != p2->hasStatus)
        return (!p1->hasStatus) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasStatus && p1->status != p2->status)
        return (p1->status < p2->status) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* SourceTimestamp */
    if(p1->hasSourceTimestamp != p2->hasSourceTimestamp)
        return (!p1->hasSourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasSourceTimestamp && p1->sourceTimestamp != p2->sourceTimestamp)
        return (p1->sourceTimestamp < p2->sourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* ServerTimestamp */
    if(p1->hasServerTimestamp != p2->hasServerTimestamp)
        return (!p1->hasServerTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasServerTimestamp && p1->serverTimestamp != p2->serverTimestamp)
        return (p1->serverTimestamp < p2->serverTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* SourcePicoseconds */
    if(p1->hasSourcePicoseconds != p2->hasSourcePicoseconds)
        return (!p1->hasSourcePicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasSourcePicoseconds && p1->sourcePicoseconds != p2->sourcePicoseconds)
        return (p1->sourcePicoseconds < p2->sourcePicoseconds) ?
            UA_ORDER_LESS : UA_ORDER_MORE;

    /* ServerPicoseconds */
    if(p1->hasServerPicoseconds != p2->hasServerPicoseconds)
        return (!p1->hasServerPicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasServerPicoseconds && p1->serverPicoseconds != p2->serverPicoseconds)
        return (p1->serverPicoseconds < p2->serverPicoseconds) ?
            UA_ORDER_LESS : UA_ORDER_MORE;

    return UA_ORDER_EQ;
}

static UA_Order
diagnosticInfoOrder(const UA_DiagnosticInfo *p1, const UA_DiagnosticInfo *p2,
                    const UA_DataType *_) {
    /* SymbolicId */
    if(p1->hasSymbolicId != p2->hasSymbolicId)
        return (!p1->hasSymbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasSymbolicId && p1->symbolicId != p2->symbolicId)
        return (p1->symbolicId < p2->symbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* NamespaceUri */
    if(p1->hasNamespaceUri != p2->hasNamespaceUri)
        return (!p1->hasNamespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasNamespaceUri && p1->namespaceUri != p2->namespaceUri)
        return (p1->namespaceUri < p2->namespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* LocalizedText */
    if(p1->hasLocalizedText != p2->hasLocalizedText)
        return (!p1->hasLocalizedText) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasLocalizedText && p1->localizedText != p2->localizedText)
        return (p1->localizedText < p2->localizedText) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* Locale */
    if(p1->hasLocale != p2->hasLocale)
        return (!p1->hasLocale) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasLocale && p1->locale != p2->locale)
        return (p1->locale < p2->locale) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* AdditionalInfo */
    if(p1->hasAdditionalInfo != p2->hasAdditionalInfo)
        return (!p1->hasAdditionalInfo) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasAdditionalInfo) {
        UA_Order o = stringOrder(&p1->additionalInfo, &p2->additionalInfo, NULL);
        if(o != UA_ORDER_EQ)
            return o;
    }

    /* InnerStatusCode */
    if(p1->hasInnerStatusCode != p2->hasInnerStatusCode)
        return (!p1->hasInnerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasInnerStatusCode && p1->innerStatusCode != p2->innerStatusCode)
        return (p1->innerStatusCode < p2->innerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* InnerDiagnosticInfo */
    if(p1->hasInnerDiagnosticInfo != p2->hasInnerDiagnosticInfo)
        return (!p1->hasInnerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->innerDiagnosticInfo == p2->innerDiagnosticInfo)
        return UA_ORDER_EQ;
    if(!p1->innerDiagnosticInfo || !p2->innerDiagnosticInfo)
        return (!p1->innerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return diagnosticInfoOrder(p1->innerDiagnosticInfo, p2->innerDiagnosticInfo, NULL);
}

static UA_Order
structureOrder(const void *p1, const void *p2, const UA_DataType *type) {
    uintptr_t u1 = (uintptr_t)p1;
    uintptr_t u2 = (uintptr_t)p2;
    UA_Order o = UA_ORDER_EQ;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        u1 += m->padding;
        u2 += m->padding;
        if(!m->isOptional) {
            if(!m->isArray) {
                o = orderJumpTable[mt->typeKind]((const void *)u1, (const void *)u2, mt);
                u1 += mt->memSize;
                u2 += mt->memSize;
            } else {
                size_t size1 = *(size_t*)u1;
                size_t size2 = *(size_t*)u2;
                u1 += sizeof(size_t);
                u2 += sizeof(size_t);
                o = arrayOrder(*(void* const*)u1, size1, *(void* const*)u2, size2, mt);
                u1 += sizeof(void*);
                u2 += sizeof(void*);
            }
        } else {
            if(!m->isArray) {
                const void *pp1 = *(void* const*)u1;
                const void *pp2 = *(void* const*)u2;
                if(pp1 == pp2) {
                    o = UA_ORDER_EQ;
                } else if(pp1 == NULL) {
                    o = UA_ORDER_LESS;
                } else if(pp2 == NULL) {
                    o = UA_ORDER_MORE;
                } else {
                    o = orderJumpTable[mt->typeKind](pp1, pp2, mt);
                }
            } else {
                size_t sa1 = *(size_t*)u1;
                size_t sa2 = *(size_t*)u2;
                u1 += sizeof(size_t);
                u2 += sizeof(size_t);
                o = arrayOrder(*(void* const*)u1, sa1, *(void* const*)u2, sa2, mt);
            }
            u1 += sizeof(void*);
            u2 += sizeof(void*);
        }

        if(o != UA_ORDER_EQ)
            break;
    }
    return o;
}

static UA_Order
unionOrder(const void *p1, const void *p2, const UA_DataType *type) {
    UA_UInt32 sel1 = *(const UA_UInt32 *)p1;
    UA_UInt32 sel2 = *(const UA_UInt32 *)p2;
    if(sel1 != sel2)
        return (sel1 < sel2) ? UA_ORDER_LESS : UA_ORDER_MORE;

    if(sel1 == 0) {
        return UA_ORDER_EQ;
    }

    const UA_DataTypeMember *m = &type->members[sel1-1];
    const UA_DataType *mt = m->memberType;

    uintptr_t u1 = ((uintptr_t)p1) + m->padding; /* includes switchfield length */
    uintptr_t u2 = ((uintptr_t)p2) + m->padding;
    if(m->isArray) {
        size_t sa1 = *(size_t*)u1;
        size_t sa2 = *(size_t*)u2;
        u1 += sizeof(size_t);
        u2 += sizeof(size_t);
        return arrayOrder(*(void* const*)u1, sa1, *(void* const*)u2, sa2, mt);
    }
    return orderJumpTable[mt->typeKind]((const void*)u1, (const void*)u2, mt);
}

static UA_Order
notImplementedOrder(const void *p1, const void *p2, const UA_DataType *type) {
    return UA_ORDER_EQ;
}

const
UA_orderSignature orderJumpTable[UA_DATATYPEKINDS] = {
    (UA_orderSignature)booleanOrder,
    (UA_orderSignature)sByteOrder,
    (UA_orderSignature)byteOrder,
    (UA_orderSignature)int16Order,
    (UA_orderSignature)uInt16Order,
    (UA_orderSignature)int32Order,
    (UA_orderSignature)uInt32Order,
    (UA_orderSignature)int64Order,
    (UA_orderSignature)uInt64Order,
    (UA_orderSignature)floatOrder,
    (UA_orderSignature)doubleOrder,
    (UA_orderSignature)stringOrder,
    (UA_orderSignature)int64Order,  /* DateTime */
    (UA_orderSignature)guidOrder,
    (UA_orderSignature)stringOrder, /* ByteString */
    (UA_orderSignature)stringOrder, /* XmlElement */
    (UA_orderSignature)nodeIdOrder,
    (UA_orderSignature)expandedNodeIdOrder,
    (UA_orderSignature)uInt32Order, /* StatusCode */
    (UA_orderSignature)qualifiedNameOrder,
    (UA_orderSignature)localizedTextOrder,
    (UA_orderSignature)extensionObjectOrder,
    (UA_orderSignature)dataValueOrder,
    (UA_orderSignature)variantOrder,
    (UA_orderSignature)diagnosticInfoOrder,
    notImplementedOrder, /* Decimal, not implemented */
    (UA_orderSignature)uInt32Order, /* Enumeration */
    (UA_orderSignature)structureOrder,
    (UA_orderSignature)structureOrder, /* Struct with Optional Fields*/
    (UA_orderSignature)unionOrder, /* Union*/
    notImplementedOrder /* BitfieldCluster, not implemented */
};

UA_Order UA_order(const void *p1, const void *p2, const UA_DataType *type) {
    return orderJumpTable[type->typeKind](p1, p2, type);
}

UA_Boolean
UA_equal(const void *p1, const void *p2, const UA_DataType *type) {
    return (UA_order(p1, p2, type) == UA_ORDER_EQ);
}

/******************/
/* Array Handling */
/******************/

void *
UA_Array_new(size_t size, const UA_DataType *type) {
    if(size > UA_INT32_MAX)
        return NULL;
    if(size == 0)
        return UA_EMPTY_ARRAY_SENTINEL;
    return UA_calloc(size, type->memSize);
}

UA_StatusCode
UA_Array_copy(const void *src, size_t size,
              void **dst, const UA_DataType *type) {
    if(size == 0) {
        if(src == NULL)
            *dst = NULL;
        else
            *dst= UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }

    /* Check the array consistency -- defensive programming in case the user
     * manually created an inconsistent array */
    if(UA_UNLIKELY(!type || !src))
        return UA_STATUSCODE_BADINTERNALERROR;

    /* calloc, so we don't have to check retval in every iteration of copying */
    *dst = UA_calloc(size, type->memSize);
    if(!*dst)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    if(type->pointerFree) {
        memcpy(*dst, src, type->memSize * size);
        return UA_STATUSCODE_GOOD;
    }

    uintptr_t ptrs = (uintptr_t)src;
    uintptr_t ptrd = (uintptr_t)*dst;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < size; ++i) {
        retval |= UA_copy((void*)ptrs, (void*)ptrd, type);
        ptrs += type->memSize;
        ptrd += type->memSize;
    }
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Array_delete(*dst, size, type);
        *dst = NULL;
    }
    return retval;
}

UA_StatusCode
UA_Array_resize(void **p, size_t *size, size_t newSize,
                const UA_DataType *type) {
    if(*size == newSize)
        return UA_STATUSCODE_GOOD;

    /* Empty array? */
    if(newSize == 0) {
        UA_Array_delete(*p, *size, type);
        *p = UA_EMPTY_ARRAY_SENTINEL;
        *size = 0;
        return UA_STATUSCODE_GOOD;
    }

    /* Make a copy of the members that shall be removed. Realloc can fail during
     * trimming. So we cannot clear the members already here. */
    void *deleteMembers = NULL;
    if(newSize < *size && !type->pointerFree) {
        size_t deleteSize = *size - newSize;
        deleteMembers = UA_malloc(deleteSize * type->memSize);
        if(!deleteMembers)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        memcpy(deleteMembers, (void*)((uintptr_t)*p + (newSize * type->memSize)),
               deleteSize * type->memSize); /* shallow copy */
    }

    void *oldP = *p;
    if(oldP == UA_EMPTY_ARRAY_SENTINEL)
        oldP = NULL;

    /* Realloc */
    void *newP = UA_realloc(oldP, newSize * type->memSize);
    if(!newP) {
        if(deleteMembers)
            UA_free(deleteMembers);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Clear removed members or initialize the new ones. Note that deleteMembers
     * depends on type->pointerFree. */
    if(newSize > *size) {
        memset((void*)((uintptr_t)newP + (*size * type->memSize)), 0,
               (newSize - *size) * type->memSize);
    } else if(deleteMembers) {
        UA_Array_delete(deleteMembers, *size - newSize, type);
    }

    /* Set the new array */
    *p = newP;
    *size = newSize;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Array_append(void **p, size_t *size, void *newElem,
                const UA_DataType *type) {
    /* Resize the array */
    size_t oldSize = *size;
    UA_StatusCode res = UA_Array_resize(p, size, oldSize+1, type);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Move the value */
    memcpy((void*)((uintptr_t)*p + (oldSize * type->memSize)),
           newElem, type->memSize);
    UA_init(newElem, type);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Array_appendCopy(void **p, size_t *size, const void *newElem,
                    const UA_DataType *type) {
    char scratch[512];
    if(type->memSize > 512)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy the value */
    UA_StatusCode res = UA_copy(newElem, (void*)scratch, type);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Append */
    res = UA_Array_append(p, size, (void*)scratch, type);
    if(res != UA_STATUSCODE_GOOD)
        UA_clear((void*)scratch, type);
    return res;
}

void
UA_Array_delete(void *p, size_t size, const UA_DataType *type) {
    if(!type->pointerFree) {
        uintptr_t ptr = (uintptr_t)p;
        for(size_t i = 0; i < size; ++i) {
            UA_clear((void*)ptr, type);
            ptr += type->memSize;
        }
    }
    UA_free((void*)((uintptr_t)p & ~(uintptr_t)UA_EMPTY_ARRAY_SENTINEL));
}

#ifdef UA_ENABLE_TYPEDESCRIPTION
UA_Boolean
UA_DataType_getStructMember(const UA_DataType *type, const char *memberName,
                            size_t *outOffset, const UA_DataType **outMemberType,
                            UA_Boolean *outIsArray) {
    if(type->typeKind != UA_DATATYPEKIND_STRUCTURE &&
       type->typeKind != UA_DATATYPEKIND_OPTSTRUCT)
        return false;

    size_t offset = 0;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        offset += m->padding;

        if(strcmp(memberName, m->memberName) == 0) {
            *outOffset = offset;
            *outMemberType = mt;
            *outIsArray = m->isArray;
            return true;
        }

        if(!m->isOptional) {
            if(!m->isArray) {
                offset += mt->memSize;
            } else {
                offset += sizeof(size_t);
                offset += sizeof(void*);
            }
        } else { /* field is optional */
            if(!m->isArray) {
                offset += sizeof(void *);
            } else {
                offset += sizeof(size_t);
                offset += sizeof(void *);
            }
        }
    }

    return false;
}
#endif

UA_Boolean
UA_DataType_isNumeric(const UA_DataType *type) {
    switch(type->typeKind) {
    case UA_DATATYPEKIND_SBYTE:
    case UA_DATATYPEKIND_BYTE:
    case UA_DATATYPEKIND_INT16:
    case UA_DATATYPEKIND_UINT16:
    case UA_DATATYPEKIND_INT32:
    case UA_DATATYPEKIND_UINT32:
    case UA_DATATYPEKIND_INT64:
    case UA_DATATYPEKIND_UINT64:
    case UA_DATATYPEKIND_FLOAT:
    case UA_DATATYPEKIND_DOUBLE:
    /* not implemented: UA_DATATYPEKIND_DECIMAL */
        return true;
    default:
        return false;
    }
}

/**********************/
/* Parse NumericRange */
/**********************/

static size_t
readDimension(UA_Byte *buf, size_t buflen, UA_NumericRangeDimension *dim) {
    size_t progress = UA_readNumber(buf, buflen, &dim->min);
    if(progress == 0)
        return 0;
    if(buflen <= progress + 1 || buf[progress] != ':') {
        dim->max = dim->min;
        return progress;
    }

    ++progress;
    size_t progress2 = UA_readNumber(&buf[progress], buflen - progress, &dim->max);
    if(progress2 == 0)
        return 0;

    /* invalid range */
    if(dim->min >= dim->max)
        return 0;

    return progress + progress2;
}

UA_StatusCode
UA_NumericRange_parse(UA_NumericRange *range, const UA_String str) {
    size_t idx = 0;
    size_t dimensionsMax = 0;
    UA_NumericRangeDimension *dimensions = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    size_t offset = 0;
    while(true) {
        /* alloc dimensions */
        if(idx >= dimensionsMax) {
            UA_NumericRangeDimension *newds;
            size_t newdssize = sizeof(UA_NumericRangeDimension) * (dimensionsMax + 2);
            newds = (UA_NumericRangeDimension*)UA_realloc(dimensions, newdssize);
            if(!newds) {
                retval = UA_STATUSCODE_BADOUTOFMEMORY;
                break;
            }
            dimensions = newds;
            dimensionsMax = dimensionsMax + 2;
        }

        /* read the dimension */
        size_t progress = readDimension(&str.data[offset], str.length - offset,
                                        &dimensions[idx]);
        if(progress == 0) {
            retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
            break;
        }
        offset += progress;
        ++idx;

        /* loop into the next dimension */
        if(offset >= str.length)
            break;

        if(str.data[offset] != ',') {
            retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
            break;
        }
        ++offset;
    }

    if(retval == UA_STATUSCODE_GOOD && idx > 0) {
        range->dimensions = dimensions;
        range->dimensionsSize = idx;
    } else {
        UA_free(dimensions);
    }

    return retval;
}

UA_NumericRange
UA_NUMERICRANGE(const char *s) {
    UA_NumericRange nr;
    memset(&nr, 0, sizeof(nr));
    UA_NumericRange_parse(&nr, UA_STRING((char*)(uintptr_t)s));
    return nr;
}

/*********************/
/* Namespace Mapping */
/*********************/

UA_UInt16
UA_NamespaceMapping_local2Remote(const UA_NamespaceMapping *nm,
                                 UA_UInt16 localIndex) {
    if(localIndex >= nm->local2remoteSize)
        return UA_UINT16_MAX - localIndex;
    return nm->local2remote[localIndex];
}

UA_UInt16
UA_NamespaceMapping_remote2Local(const UA_NamespaceMapping *nm,
                                 UA_UInt16 remoteIndex) {
    if(remoteIndex >= nm->remote2localSize)
        return UA_UINT16_MAX - remoteIndex;
    return nm->remote2local[remoteIndex];
}

/* Returns an error if the uri was not found.
 * The pointer to the index argument needs to be non-NULL. */
UA_StatusCode
UA_NamespaceMapping_uri2Index(const UA_NamespaceMapping *nm,
                              UA_String uri, UA_UInt16 *index) {
    for(size_t i = 0; i < nm->namespaceUrisSize; i++) {
        if(UA_String_equal(&uri, &nm->namespaceUris[i])) {
            *index = (UA_UInt16)i;
            return UA_STATUSCODE_GOOD;
        }
    }
    return UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
UA_NamespaceMapping_index2Uri(const UA_NamespaceMapping *nm,
                              UA_UInt16 index, UA_String *uri) {
    if(nm->namespaceUrisSize <= index)
        return UA_STATUSCODE_BADNOTFOUND;
    *uri = nm->namespaceUris[index];
    return UA_STATUSCODE_GOOD;
}

void
UA_NamespaceMapping_clear(UA_NamespaceMapping *nm) {
    if(!nm)
        return;
    UA_Array_delete(nm->namespaceUris, nm->namespaceUrisSize, &UA_TYPES[UA_TYPES_STRING]);
    UA_Array_delete(nm->local2remote, nm->local2remoteSize, &UA_TYPES[UA_TYPES_UINT16]);
    UA_Array_delete(nm->remote2local, nm->remote2localSize, &UA_TYPES[UA_TYPES_UINT16]);
}

void
UA_NamespaceMapping_delete(UA_NamespaceMapping *nm) {
    UA_NamespaceMapping_clear(nm);
    UA_free(nm);
}

/**** amalgamated original file "/src/ua_types_definition.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2025 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


/*************************/
/* Generic Functionality */
/*************************/

/* All descriptions begin with UA_DataTypeDescription */

#ifdef UA_TYPES_STRUCTUREDESCRIPTION

static UA_StatusCode
fromDescription(UA_DataType *type, const UA_DataTypeDescription *descr) {
    memset(type, 0, sizeof(UA_DataType));
    UA_StatusCode res = UA_NodeId_copy(&descr->dataTypeId, &type->typeId);
    if(res != UA_STATUSCODE_GOOD)
        return res;

#ifdef UA_ENABLE_TYPEDESCRIPTION
    UA_Byte bufChars[512];
    UA_ByteString buf = {512, bufChars};
    res = UA_QualifiedName_print(&descr->name, &buf);
    UA_CHECK_STATUS(res, UA_DataType_clear(type); return res);

    type->typeName = (char*)UA_malloc(buf.length + 1);
    UA_CHECK(type->typeName != 0,
             UA_DataType_clear(type); return UA_STATUSCODE_BADOUTOFMEMORY);
    memcpy((void*)(uintptr_t)type->typeName, buf.data, buf.length);
    *(char*)(uintptr_t)&type->typeName[buf.length] = '\0';
#endif

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
toDescription(const UA_DataType *type, UA_DataTypeDescription *descr) {
    /* Parse the typeName into the BrowseName (QualifiedName) */
    UA_StatusCode res;
#ifdef UA_ENABLE_TYPEDESCRIPTION
    UA_String nameStr = UA_STRING((char*)(uintptr_t)type->typeName);
    res = UA_QualifiedName_parse(&descr->name, nameStr);
    if(res != UA_STATUSCODE_GOOD)
        return res;
#endif

    /* Copy the NodeId */
    res = UA_NodeId_copy(&type->typeId, &descr->dataTypeId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_QualifiedName_clear(&descr->name);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

/******************/
/* Structure Type */
/******************/

/* Compute padding of structure elements based on the alignment requirements
 * of the builtin datatypes */

#define PADSTRUCT(T) struct _pad_##T {char _; T x;};
#define ALIGNMENT(T) offsetof(struct _pad_##T, x)
#define PADDING(MEMSIZE, ALIGN) (ALIGN - (MEMSIZE % ALIGN)) % ALIGN

PADSTRUCT(UA_Boolean)
PADSTRUCT(UA_SByte)
PADSTRUCT(UA_Byte)
PADSTRUCT(UA_Int16)
PADSTRUCT(UA_UInt16)
PADSTRUCT(UA_Int32)
PADSTRUCT(UA_UInt32)
PADSTRUCT(UA_Int64)
PADSTRUCT(UA_UInt64)
PADSTRUCT(UA_Float)
PADSTRUCT(UA_Double)
PADSTRUCT(UA_String)
PADSTRUCT(UA_DateTime)
PADSTRUCT(UA_Guid)
PADSTRUCT(UA_ByteString)
PADSTRUCT(UA_XmlElement)
PADSTRUCT(UA_NodeId)
PADSTRUCT(UA_ExpandedNodeId)
PADSTRUCT(UA_StatusCode)
PADSTRUCT(UA_QualifiedName)
PADSTRUCT(UA_LocalizedText)
PADSTRUCT(UA_ExtensionObject)
PADSTRUCT(UA_DataValue)
PADSTRUCT(UA_Variant)
PADSTRUCT(UA_DiagnosticInfo)

PADSTRUCT(uintptr_t)
PADSTRUCT(size_t)

/* TODO: Decimal and BitfieldCluster are not implemented in the SDK so far */
static UA_Byte alignment[UA_DATATYPEKINDS] = {
    ALIGNMENT(UA_Boolean), ALIGNMENT(UA_SByte), ALIGNMENT(UA_Byte), ALIGNMENT(UA_Int16),
    ALIGNMENT(UA_UInt16), ALIGNMENT(UA_Int32), ALIGNMENT(UA_UInt32), ALIGNMENT(UA_Int64),
    ALIGNMENT(UA_UInt64), ALIGNMENT(UA_Float), ALIGNMENT(UA_Double), ALIGNMENT(UA_String),
    ALIGNMENT(UA_DateTime), ALIGNMENT(UA_Guid), ALIGNMENT(UA_ByteString),
    ALIGNMENT(UA_XmlElement), ALIGNMENT(UA_NodeId), ALIGNMENT(UA_ExpandedNodeId),
    ALIGNMENT(UA_StatusCode), ALIGNMENT(UA_QualifiedName), ALIGNMENT(UA_LocalizedText),
    ALIGNMENT(UA_ExtensionObject), ALIGNMENT(UA_DataValue), ALIGNMENT(UA_Variant),
    ALIGNMENT(UA_DiagnosticInfo), 0, ALIGNMENT(UA_UInt32), 0, 0, 0, 0
};

static UA_Byte
type_alignment(const UA_DataType *type) {
    if(type->typeKind == UA_DATATYPEKIND_STRUCTURE ||
       type->typeKind == UA_DATATYPEKIND_OPTSTRUCT ||
       type->typeKind == UA_DATATYPEKIND_UNION) {
        /* Maximum alignment of any member */
        UA_Byte align = 1;
        for(size_t i = 0; i < type->membersSize; i++) {
            const UA_DataTypeMember *dtm = &type->members[i];
            if(dtm->isArray) {
                UA_Byte sizeAlign = offsetof(struct _pad_size_t, x);
                if(sizeAlign> align)
                    align = sizeAlign;
            }
            if(dtm->isArray || dtm->isOptional) {
                UA_Byte ptrAlign = offsetof(struct _pad_uintptr_t, x);
                if(ptrAlign> align)
                    align = ptrAlign;
                continue;
            }
            UA_Byte memberAlign = type_alignment(type->members[i].memberType);
            if(memberAlign > align)
                align = memberAlign;
        }
        return align;
    }
    return alignment[type->typeKind];
}

/* The functions below require StructureDescription, EnumDescription,
 * and SimpleTypeDescription which are derived from UA_DataTypeDescription.
 * They are available when UA_TYPES_STRUCTUREDESCRIPTION is defined
 * (guarded by the #ifdef at the top of this file). */

static UA_StatusCode
UA_DataType_fromStructureDescription(UA_DataType *type,
                                     const UA_StructureDescription *descr,
                                     const UA_DataTypeArray *customTypes) {
    /* Set the basic description */
    UA_StatusCode res = fromDescription(type, (const UA_DataTypeDescription*)descr);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Set the typeKind */
    const UA_StructureDefinition *sd = &descr->structureDefinition;
    switch(sd->structureType) {
    case UA_STRUCTURETYPE_STRUCTURE:
        type->typeKind = UA_DATATYPEKIND_STRUCTURE; break;
    case UA_STRUCTURETYPE_STRUCTUREWITHOPTIONALFIELDS:
        type->typeKind = UA_DATATYPEKIND_OPTSTRUCT; break;
    case UA_STRUCTURETYPE_UNION:
        type->typeKind = UA_DATATYPEKIND_UNION; break;
    case UA_STRUCTURETYPE_STRUCTUREWITHSUBTYPEDVALUES:
    case UA_STRUCTURETYPE_UNIONWITHSUBTYPEDVALUES:
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    default: return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Copy NodeIds */
    res = UA_NodeId_copy(&sd->defaultEncodingId, &type->binaryEncodingId);
    UA_CHECK_STATUS(res, UA_DataType_clear(type); return res);

    /* Allocate the members array */
    type->members = (UA_DataTypeMember *)
        UA_calloc(sd->fieldsSize, sizeof(UA_DataTypeMember));
    if((sd->fieldsSize > 0) && !type->members) {
        UA_DataType_clear(type);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    type->membersSize = (UA_Byte)sd->fieldsSize;

    /* Try to get pointerFree and overlayable handling shortcuts.
     * Adjusted later for each member and end-padding. */
    if(sd->structureType == UA_STRUCTURETYPE_STRUCTURE) {
        type->pointerFree = true;
        type->overlayable = true;
    } else if(sd->structureType == UA_STRUCTURETYPE_UNION) {
        type->pointerFree = true;
    }

    /* Populate the members array */
    for(size_t i = 0; i < sd->fieldsSize; i++) {
        const UA_StructureField *sf = &sd->fields[i];
        UA_DataTypeMember *dtm = &type->members[i];

        /* Find the referenced type */
        dtm->memberType = UA_findDataTypeWithCustom(&sf->dataType, customTypes);
        if(!dtm->memberType) {
            UA_DataType_clear(type);
            return UA_STATUSCODE_BADNOTFOUND;
        }

        /* Update handling shortcuts */
        type->pointerFree &= dtm->memberType->pointerFree;
        type->overlayable &= dtm->memberType->overlayable;

        /* Copy the member name */
#ifdef UA_ENABLE_TYPEDESCRIPTION
        dtm->memberName = (char*)UA_malloc(sf->name.length + 1);
        UA_CHECK(dtm->memberName != NULL,
                 UA_DataType_clear(type); return UA_STATUSCODE_BADOUTOFMEMORY);
        memcpy((char*)(uintptr_t)dtm->memberName, sf->name.data, sf->name.length);
        *(char*)(uintptr_t)&dtm->memberName[sf->name.length] = '\0';
#endif

        /* Memory size and padding for the scalar case */
        UA_Byte talignment = type_alignment(dtm->memberType);
        size_t memSize = dtm->memberType->memSize;
        dtm->padding = PADDING(type->memSize, talignment);

        /* Handle valuerank and array dimensions */
        if(sf->valueRank == 1) {
            /* 1D-array */
            if(sf->arrayDimensionsSize > 1 ||
               (sf->arrayDimensionsSize == 1 && sf->arrayDimensions[0] != 0)) {
                UA_DataType_clear(type);
                return UA_STATUSCODE_BADINTERNALERROR;
            }
            dtm->isArray = true;
            memSize = sizeof(void*) + sizeof(size_t);
            dtm->padding = PADDING(type->memSize, offsetof(struct _pad_size_t, x));
            type->pointerFree = false; /* array is not pointer-free */
        } else if(sf->valueRank != UA_VALUERANK_SCALAR) {
            /* Only 1D-arrays or scalars are allowed */
            UA_DataType_clear(type);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        /* Handle isOptional */
        if(sf->isOptional) {
            if(type->typeKind != UA_DATATYPEKIND_OPTSTRUCT) {
                UA_DataType_clear(type);
                return UA_STATUSCODE_BADINTERNALERROR;
            }
            dtm->isOptional = true;
            if(!dtm->isArray) {
                memSize = sizeof(void*);
                dtm->padding = PADDING(type->memSize, offsetof(struct _pad_uintptr_t, x));
            }
            UA_assert(!type->pointerFree); /* Set above */
        }

        /* For unions, leave space for the switchfield in the padding */
        if(type->typeKind == UA_DATATYPEKIND_UNION) {
            UA_Byte fieldPadding = (UA_Byte)((dtm->isArray) ?
                PADDING(sizeof(UA_UInt32), offsetof(struct _pad_size_t, x)) :
                PADDING(sizeof(UA_UInt32), type_alignment(dtm->memberType)));
            dtm->padding = sizeof(UA_UInt32) + fieldPadding;
        }

        /* Adjust the type size for the latest member */
        if(type->typeKind == UA_DATATYPEKIND_UNION) {
            /* Increase the memSize if the current member is the largest */
            if(memSize + dtm->padding > type->memSize)
                type->memSize = (UA_UInt16)(memSize + dtm->padding);
        } else {
            /* Increase the memSize for the current member */
            type->memSize += (UA_UInt16)(memSize + dtm->padding);
        }

        /* Overlayable types cannot have padding */
        if(dtm->padding > 0)
            type->overlayable = false;

        /* TODO: MaxStringLength */
    }

    /* Add final padding according to the member alignment requirements */
    UA_Byte self_alignment = type_alignment(type);
    UA_Byte end_padding = (UA_Byte)(PADDING(type->memSize, self_alignment));
    type->memSize += end_padding;

    /* Finalize handling shortcuts. Types with pointer are never overlayable.  */
    if(end_padding > 0)
        type->overlayable = false;
    type->overlayable &= type->pointerFree;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataType_toStructureDescription(const UA_DataType *type,
                                   UA_StructureDescription *descr) {
    UA_StructureDescription_init(descr);

    UA_StatusCode res = toDescription(type, (UA_DataTypeDescription *)descr);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Check if the type can be described by a StructureDefinition.
     * Set baseType and structureType. */
    UA_StructureDefinition *sd = &descr->structureDefinition;
    if(type->typeKind == UA_DATATYPEKIND_STRUCTURE) {
        sd->baseDataType = UA_NS0ID(STRUCTURE);
        sd->structureType = UA_STRUCTURETYPE_STRUCTURE;
    } else if(type->typeKind == UA_DATATYPEKIND_OPTSTRUCT) {
        sd->baseDataType = UA_NS0ID(STRUCTURE);
        sd->structureType = UA_STRUCTURETYPE_STRUCTUREWITHOPTIONALFIELDS;
    } else if(type->typeKind == UA_DATATYPEKIND_UNION) {
        sd->baseDataType = UA_NS0ID(UNION);
        sd->structureType = UA_STRUCTURETYPE_UNION;
    } else {
        UA_StructureDescription_clear(descr);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Set the DefaultEncodingId */
    res = UA_NodeId_copy(&type->binaryEncodingId, &sd->defaultEncodingId);
    UA_CHECK_STATUS(res, UA_StructureDescription_clear(descr); return res);

    /* Allocate the fields */
    sd->fields = (UA_StructureField*)
        UA_calloc(type->membersSize, sizeof(UA_StructureField));
    if((type->membersSize > 0) && !sd->fields) {
        UA_StructureDescription_clear(descr);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    sd->fieldsSize = type->membersSize;

    /* Populate the fields */
    for(size_t i = 0; i < type->membersSize; i++) {
        UA_StructureField *sf = &sd->fields[i];
        const UA_DataTypeMember *dtm = &type->members[i];
#ifdef UA_ENABLE_TYPEDESCRIPTION
        sf->name = UA_String_fromChars(dtm->memberName);
#endif
        res |= UA_NodeId_copy(&dtm->memberType->typeId, &sf->dataType);
        sf->valueRank = (dtm->isArray) ? UA_VALUERANK_ONE_DIMENSION : UA_VALUERANK_SCALAR;
        sf->isOptional = dtm->isOptional;
        if(dtm->isArray && (type->typeKind == UA_DATATYPEKIND_STRUCTURE ||
                            type->typeKind == UA_DATATYPEKIND_OPTSTRUCT)) {
            sf->arrayDimensions = (UA_UInt32*)UA_malloc(sizeof(UA_UInt32));
            if(!sf->arrayDimensions) {
                UA_StructureDescription_clear(descr);
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            sf->arrayDimensionsSize = 1;
            *sf->arrayDimensions = 0;
        }
    }

    if(res != UA_STATUSCODE_GOOD)
        UA_StructureDescription_clear(descr);
    return res;
}

/*************/
/* Enum Type */
/*************/

static UA_StatusCode
UA_DataType_fromEnumDescription(UA_DataType *type,
                                const UA_EnumDescription *descr) {
    /* If the builtInType is Int32, the DataType is an Enumeration. If the
     * builtInType is one of the UInteger DataTypes or ExtensionObject, the
     * DataType is an OptionSet. */
    if(descr->builtInType != UA_DATATYPEKIND_INT32 + 1)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    /* Set the basic description */
    UA_StatusCode res = fromDescription(type, (const UA_DataTypeDescription*)descr);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Set the enum description */
    type->typeKind = UA_DATATYPEKIND_ENUM;
    type->memSize = sizeof(UA_Int32);
    type->pointerFree = true;
    type->overlayable = true;

    /* Allocate the members array */
    type->members = (UA_DataTypeMember *)
        UA_calloc(descr->enumDefinition.fieldsSize, sizeof(UA_DataTypeMember));
    if((descr->enumDefinition.fieldsSize > 0) && !type->members) {
        UA_DataType_clear(type);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    type->membersSize = (UA_Byte)descr->enumDefinition.fieldsSize;

    /* Copy the enum fields into the members array */
    for(size_t i = 0; i < type->membersSize; i++) {
        UA_DataTypeMember *dtm = &type->members[i];
        const UA_EnumField *ef = &descr->enumDefinition.fields[i];
        dtm->memberType = (const UA_DataType*)(uintptr_t)ef->value;
        dtm->memberName = (char*)UA_malloc(ef->name.length + 1);
        UA_CHECK(dtm->memberName != NULL,
                 UA_DataType_clear(type); return UA_STATUSCODE_BADOUTOFMEMORY);
        memcpy((char*)(uintptr_t)dtm->memberName, ef->name.data, ef->name.length);
        *(char*)(uintptr_t)&dtm->memberName[ef->name.length] = '\0';
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataType_toEnumDescription(const UA_DataType *type,
                              UA_EnumDescription *descr) {
    UA_StatusCode res = toDescription(type, (UA_DataTypeDescription *)descr);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Set the builtin type */
    descr->builtInType = UA_DATATYPEKIND_INT32 + 1;

    /* Allocate the enum fields */
    descr->enumDefinition.fields = (UA_EnumField*)
        UA_calloc(type->membersSize, sizeof(UA_EnumField));
    if((type->membersSize > 0) && !descr->enumDefinition.fields) {
        UA_EnumDescription_clear(descr);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    descr->enumDefinition.fieldsSize = type->membersSize;

    /* Set the enum fields */
    for(size_t i = 0; i < type->membersSize; i++) {
        const UA_DataTypeMember *dtm = &type->members[i];
        UA_EnumField *ef = &descr->enumDefinition.fields[i];
        ef->value = (UA_Int64)(uintptr_t)dtm->memberType;
#ifdef UA_ENABLE_TYPEDESCRIPTION
        ef->name = UA_STRING_ALLOC(dtm->memberName);
        ef->displayName = UA_LOCALIZEDTEXT_ALLOC("", dtm->memberName);
#endif
    }

    return UA_STATUSCODE_GOOD;
}

/***************/
/* Simple Type */
/***************/

static UA_StatusCode
UA_DataType_fromSimpleTypeDescription(UA_DataType *type,
                                      const UA_SimpleTypeDescription *descr) {
    /* Check if the BuiltinType is a "simple type" */
    if(descr->builtInType > 0 &&
       descr->builtInType > UA_DATATYPEKIND_DIAGNOSTICINFO + 1)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Set the basic description. Then use defaults from the builtin type */
    UA_StatusCode res = fromDescription(type, (const UA_DataTypeDescription*)descr);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Set the type description */
    type->typeKind = UA_TYPES[descr->builtInType-1].typeKind;
    type->memSize = UA_TYPES[descr->builtInType-1].memSize;
    type->pointerFree = UA_TYPES[descr->builtInType-1].pointerFree;
    type->overlayable = UA_TYPES[descr->builtInType-1].overlayable;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataType_toSimpleTypeDescription(const UA_DataType *type,
                                    UA_SimpleTypeDescription *descr) {
    /* Check if the BuiltinType is a "simple type" */
    if(type->typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO)
        return UA_STATUSCODE_BADINTERNALERROR;

    const UA_DataType *baseType = &UA_TYPES[type->typeKind];
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= toDescription(type, (UA_DataTypeDescription *)descr);
    res |= UA_NodeId_copy(&baseType->typeId, &descr->baseDataType);
    descr->builtInType = type->typeKind + 1;

    if(res != UA_STATUSCODE_GOOD)
        UA_SimpleTypeDescription_clear(descr);
    return res;
}

/**************/
/* Public API */
/**************/

UA_StatusCode
UA_DataType_fromDescription(UA_DataType *type, const UA_ExtensionObject *descr,
                            const UA_DataTypeArray *customTypes) {
    void *data = descr->content.decoded.data;
    if(UA_ExtensionObject_hasDecodedType(descr, &UA_TYPES[UA_TYPES_SIMPLETYPEDESCRIPTION]))
        return UA_DataType_fromSimpleTypeDescription(type, (UA_SimpleTypeDescription*)data);
    if(UA_ExtensionObject_hasDecodedType(descr, &UA_TYPES[UA_TYPES_ENUMDESCRIPTION]))
        return UA_DataType_fromEnumDescription(type, (UA_EnumDescription*)data);
    if(UA_ExtensionObject_hasDecodedType(descr, &UA_TYPES[UA_TYPES_STRUCTUREDESCRIPTION]))
        return UA_DataType_fromStructureDescription(type, (UA_StructureDescription*)data, customTypes);
    return UA_STATUSCODE_BADINVALIDARGUMENT;
}

UA_StatusCode
UA_DataType_toDescription(const UA_DataType *type, UA_ExtensionObject *descr) {
    UA_ExtensionObject_init(descr);
    void *descr_data = NULL;
    const UA_DataType *descr_type = NULL;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(type->typeKind) {
    case UA_DATATYPEKIND_ENUM:
        descr_data = UA_EnumDescription_new();
        if(!descr_data)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        descr_type = &UA_TYPES[UA_TYPES_ENUMDESCRIPTION];
        res = UA_DataType_toEnumDescription(type,
                          (UA_EnumDescription*)descr_data);
        break;
    case UA_DATATYPEKIND_STRUCTURE:
    case UA_DATATYPEKIND_OPTSTRUCT:
    case UA_DATATYPEKIND_UNION:
        descr_data = UA_StructureDescription_new();
        if(!descr_data)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        descr_type = &UA_TYPES[UA_TYPES_STRUCTUREDESCRIPTION];
        res = UA_DataType_toStructureDescription(type,
                          (UA_StructureDescription*)descr_data);
        break;
    default:
        descr_data = UA_SimpleTypeDescription_new();
        if(!descr_data)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        descr_type = &UA_TYPES[UA_TYPES_SIMPLETYPEDESCRIPTION];
        res = UA_DataType_toSimpleTypeDescription(type,
                          (UA_SimpleTypeDescription*)descr_data);
        break;
    }

    if(res != UA_STATUSCODE_GOOD) {
        UA_free(descr_data);
        return res;
    }

    UA_ExtensionObject_setValue(descr, descr_data, descr_type);
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_TYPES_STRUCTUREDESCRIPTION */

/**** amalgamated original file "/src/ua_types_encoding_binary.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2020 (c) Grigory Fridman
 *    Copyright 2014-2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014 (c) Leon Urbas
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Henrik Norrman
 */



/**
 * Type Encoding and Decoding
 * --------------------------
 * The following methods contain encoding and decoding functions for the builtin
 * data types and generic functions that operate on all types and arrays. This
 * requires the type description from a UA_DataType structure.
 *
 * Breaking a message up into chunks is integrated with the encoding. When the
 * end of a buffer is reached, a callback is executed that sends the current
 * buffer as a chunk and exchanges the encoding buffer "underneath" the ongoing
 * encoding. This reduces the RAM requirements and unnecessary copying. */

/* Part 6 §5.1.5: Decoders shall support at least 100 nesting levels */
#define UA_ENCODING_MAX_RECURSION 100

void *
ctxCalloc(Ctx *ctx, size_t nelem, size_t elsize) {
    if(ctx->opts.calloc)
        return ctx->opts.calloc(ctx->opts.callocContext, nelem, elsize);
    return UA_calloc(nelem, elsize);
}

void
ctxFree(Ctx *ctx, void *p) {
    if(ctx->opts.calloc)
        return;
    UA_free(p);
}

void
ctxClear(Ctx *ctx, void *p, const UA_DataType *type) {
    if(!ctx->opts.calloc)
        UA_clear(p, type);
    else
        memset(p, 0, type->memSize);
}

static void
ctxClearNodeId(Ctx *ctx, UA_NodeId *p) {
    if((p->identifierType == UA_NODEIDTYPE_STRING ||
        p->identifierType == UA_NODEIDTYPE_BYTESTRING) &&
       !ctx->opts.calloc && p->identifier.string.data > (u8*)UA_EMPTY_ARRAY_SENTINEL)
        UA_free(p->identifier.string.data);
    memset(p, 0, sizeof(UA_NodeId));
}

#define FUNC_ENCODE_BINARY(TYPE) static status                          \
    TYPE##_encodeBinary(Ctx *UA_RESTRICT ctx,                           \
                        const void *UA_RESTRICT _src,                   \
                        const UA_DataType *type)
#define FUNC_DECODE_BINARY(TYPE) static status                          \
    TYPE##_decodeBinary(Ctx *UA_RESTRICT ctx,                           \
                        void *UA_RESTRICT _dst,                         \
                        const UA_DataType *type)
#define ENCODE_DIRECT(SRC, TYPE) TYPE##_encodeBinary(ctx, (SRC), NULL)
#define DECODE_DIRECT(DST, TYPE) TYPE##_decodeBinary(ctx, (DST), NULL)

#define IF_CHECK_BUFSIZE(check)                             \
    if(!UA_LIKELY(check)) {                                 \
        if(ctx->end != NULL)                                \
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; \
    } else                                                  \

/* Send the current chunk and replace the buffer */
static status exchangeBuffer(Ctx *ctx) {
    if(!ctx->exchangeBufferCallback)
        return UA_STATUSCODE_BADENCODINGERROR;
    return ctx->exchangeBufferCallback(ctx->exchangeBufferCallbackHandle,
                                       &ctx->pos, &ctx->end);
}

/* If encoding fails, exchange the buffer and try again. */
static status
encodeWithExchangeBuffer(Ctx *ctx, const void *ptr, const UA_DataType *type) {
    u8 *oldpos = ctx->pos; /* Last known good position */
/**
 * It is often forgotten to include -DNDEBUG in the compiler flags when using the single-file release.
 * So we make assertions dependent on the UA_DEBUG definition handled by CMake. */
#ifdef UA_DEBUG
    /* We have to ensure that the buffer was not exchanged AND
     * BADENCODINGLIMITSEXCEEDED was returned. If that were the case, oldpos
     * would be invalid. That means, a type encoding must never return
     * BADENCODINGLIMITSEXCEEDED once the buffer could have been exchanged. This
     * is achieved by the use of encodeWithExchangeBuffer. */
    const u8 *oldend = ctx->end;
    (void)oldend; /* For compilers who don't understand NDEBUG... */
#endif
    status ret = encodeBinaryJumpTable[type->typeKind](ctx, ptr, type);
    if(ret == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) {
        UA_assert(ctx->end == oldend);
        ctx->pos = oldpos; /* Set to the last known good position and exchange */
        ret = exchangeBuffer(ctx);
        UA_CHECK_STATUS(ret, return ret);
        ret = encodeBinaryJumpTable[type->typeKind](ctx, ptr, type);
    }
    return ret;
}

/*****************/
/* Integer Types */
/*****************/

#if !UA_BINARY_OVERLAYABLE_INTEGER

#pragma message "Integer endianness could not be detected to be little endian. Use slow generic encoding."

/* These en/decoding functions are only used when the architecture isn't little-endian. */
static void
UA_encode16(const u16 v, u8 buf[2]) {
    buf[0] = (u8)v;
    buf[1] = (u8)(v >> 8);
}

static void
UA_decode16(const u8 buf[2], u16 *v) {
    *v = (u16)((u16)buf[0] + (((u16)buf[1]) << 8));
}

static void
UA_encode32(const u32 v, u8 buf[4]) {
    buf[0] = (u8)v;
    buf[1] = (u8)(v >> 8);
    buf[2] = (u8)(v >> 16);
    buf[3] = (u8)(v >> 24);
}

static void
UA_decode32(const u8 buf[4], u32 *v) {
    *v = (u32)((u32)buf[0] + (((u32)buf[1]) << 8) +
             (((u32)buf[2]) << 16) + (((u32)buf[3]) << 24));
}

static void
UA_encode64(const u64 v, u8 buf[8]) {
    buf[0] = (u8)v;
    buf[1] = (u8)(v >> 8);
    buf[2] = (u8)(v >> 16);
    buf[3] = (u8)(v >> 24);
    buf[4] = (u8)(v >> 32);
    buf[5] = (u8)(v >> 40);
    buf[6] = (u8)(v >> 48);
    buf[7] = (u8)(v >> 56);
}

static void
UA_decode64(const u8 buf[8], u64 *v) {
    *v = (u64)((u64)buf[0] + (((u64)buf[1]) << 8) +
             (((u64)buf[2]) << 16) + (((u64)buf[3]) << 24) +
             (((u64)buf[4]) << 32) + (((u64)buf[5]) << 40) +
             (((u64)buf[6]) << 48) + (((u64)buf[7]) << 56));
}

#endif /* !UA_BINARY_OVERLAYABLE_INTEGER */

/* Boolean */
/* Note that sizeof(bool) != 1 on some platforms. Overlayable integer encoding
 * is disabled in those cases. */
FUNC_ENCODE_BINARY(Boolean) {
    const UA_Boolean *src = (const UA_Boolean*)_src;
    IF_CHECK_BUFSIZE(ctx->pos + 1 <= ctx->end) {
        *ctx->pos = *(const u8*)src;
    }
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

FUNC_DECODE_BINARY(Boolean) {
    UA_Boolean *dst = (UA_Boolean*)_dst;
    UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADDECODINGERROR);
    *dst = (*ctx->pos > 0) ? true : false;
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

/* Byte */
FUNC_ENCODE_BINARY(Byte) {
    const UA_Byte *src = (const UA_Byte*)_src;
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u8) <= ctx->end) {
        *ctx->pos = *(const u8*)src;
    }
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

FUNC_DECODE_BINARY(Byte) {
    UA_Byte *dst = (UA_Byte*)_dst;
    UA_CHECK(ctx->pos + sizeof(u8) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
    *dst = *ctx->pos;
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

/* UInt16 */
FUNC_ENCODE_BINARY(UInt16) {
    const UA_UInt16 *src = (const UA_UInt16*)_src;
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u16) <= ctx->end) {
#if UA_BINARY_OVERLAYABLE_INTEGER
        memcpy(ctx->pos, src, sizeof(u16));
#else
        UA_encode16(*src, ctx->pos);
#endif
    }
    ctx->pos += 2;
    return UA_STATUSCODE_GOOD;
}

FUNC_DECODE_BINARY(UInt16) {
    UA_UInt16 *dst = (UA_UInt16*)_dst;
    UA_CHECK(ctx->pos + sizeof(u16) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
#if UA_BINARY_OVERLAYABLE_INTEGER
    memcpy(dst, ctx->pos, sizeof(u16));
#else
    UA_decode16(ctx->pos, dst);
#endif
    ctx->pos += 2;
    return UA_STATUSCODE_GOOD;
}

/* UInt32 */
FUNC_ENCODE_BINARY(UInt32) {
    const UA_UInt32 *src = (const UA_UInt32*)_src;
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u32) <= ctx->end) {
#if UA_BINARY_OVERLAYABLE_INTEGER
        memcpy(ctx->pos, src, sizeof(u32));
#else
        UA_encode32(*src, ctx->pos);
#endif
    }
    ctx->pos += 4;
    return UA_STATUSCODE_GOOD;
}

FUNC_DECODE_BINARY(UInt32) {
    UA_UInt32 *dst = (UA_UInt32*)_dst;
    UA_CHECK(ctx->pos + sizeof(u32) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
#if UA_BINARY_OVERLAYABLE_INTEGER
    memcpy(dst, ctx->pos, sizeof(u32));
#else
    UA_decode32(ctx->pos, dst);
#endif
    ctx->pos += 4;
    return UA_STATUSCODE_GOOD;
}

/* UInt64 */
FUNC_ENCODE_BINARY(UInt64) {
    const UA_UInt64 *src = (const UA_UInt64*)_src;
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u64) <= ctx->end) {
#if UA_BINARY_OVERLAYABLE_INTEGER
        memcpy(ctx->pos, src, sizeof(u64));
#else
        UA_encode64(*src, ctx->pos);
#endif
    }
    ctx->pos += 8;
    return UA_STATUSCODE_GOOD;
}

FUNC_DECODE_BINARY(UInt64) {
    UA_UInt64 *dst = (UA_UInt64*)_dst;
    UA_CHECK(ctx->pos + sizeof(u64) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
#if UA_BINARY_OVERLAYABLE_INTEGER
    memcpy(dst, ctx->pos, sizeof(u64));
#else
    UA_decode64(ctx->pos, dst);
#endif
    ctx->pos += 8;
    return UA_STATUSCODE_GOOD;
}

/************************/
/* Floating Point Types */
/************************/

/* Can we reuse the integer encoding mechanism by casting floating point
 * values? For single float values we ensure that only quiet NAN are used.
 * For float arrays we want to have the speed advantage of just memcpy (if
 * the processor architecture uses IEE754). We get array-memcpy by the
 * "overlayable" bit in the datatype description. */

#if (UA_FLOAT_IEEE754 < 1) || (UA_LITTLE_ENDIAN != UA_FLOAT_LITTLE_ENDIAN)
#include <math.h>
#define UA_SLOW_IEEE754 1
#pragma message "No native IEEE 754 format detected. Use slow generic encoding."

/* Handling of IEEE754 floating point values was taken from Beej's Guide to
 * Network Programming (http://beej.us/guide/bgnet/) and enhanced to cover the
 * edge cases +/-0, +/-inf and nan. */
static uint64_t
pack754(long double f, unsigned bits, unsigned expbits) {
    unsigned significandbits = bits - expbits - 1;
    long double fnorm;
    long long sign;
    if(f < 0) { sign = 1; fnorm = -f; }
    else { sign = 0; fnorm = f; }
    int shift = 0;
    while(fnorm >= 2.0) { fnorm /= 2.0; ++shift; }
    while(fnorm < 1.0) { fnorm *= 2.0; --shift; }
    fnorm = fnorm - 1.0;
    long long significand = (long long)(fnorm * ((float)(1LL<<significandbits) + 0.5f));
    long long exponent = shift + ((1<<(expbits-1)) - 1);
    return (uint64_t)((sign<<(bits-1)) | (exponent<<(bits-expbits-1)) | significand);
}

static long double
unpack754(uint64_t i, unsigned bits, unsigned expbits) {
    unsigned significandbits = bits - expbits - 1;
    long double result = (long double)(i&(uint64_t)((1LL<<significandbits)-1));
    result /= (long double)(1LL<<significandbits);
    result += 1.0f;
    unsigned bias = (unsigned)(1<<(expbits-1)) - 1;
    long long shift = (long long)((i>>significandbits) & (uint64_t)((1LL<<expbits)-1)) - bias;
    while(shift > 0) { result *= 2.0; --shift; }
    while(shift < 0) { result /= 2.0; ++shift; }
    result *= ((i>>(bits-1))&1)? -1.0: 1.0;
    return result;
}

#endif

/* Float */
#define FLOAT_NAN 0xffc00000
#define FLOAT_INF 0x7f800000
#define FLOAT_NEG_INF 0xff800000
#define FLOAT_NEG_ZERO 0x80000000

FUNC_ENCODE_BINARY(Float) {
    const UA_Float *src = (const UA_Float*)_src;
    UA_Float f = *src;
    u32 encoded;
    if(UA_UNLIKELY(f != f)) encoded = FLOAT_NAN; /* quit NAN */
#ifndef UA_SLOW_IEEE754
    else memcpy(&encoded, &f, sizeof(UA_Float));
#else
    else if(f == 0.0f) encoded = signbit(f) ? FLOAT_NEG_ZERO : 0;
    else if(f/f != f/f) encoded = f > 0 ? FLOAT_INF : FLOAT_NEG_INF;
    else encoded = (u32)pack754(f, 32, 8);
#endif
    return ENCODE_DIRECT(&encoded, UInt32);
}

FUNC_DECODE_BINARY(Float) {
    UA_Float *dst = (UA_Float*)_dst;
    u32 decoded;
    status ret = DECODE_DIRECT(&decoded, UInt32);
    UA_CHECK_STATUS(ret, return ret);
#ifndef UA_SLOW_IEEE754
    if(UA_UNLIKELY((decoded >= 0x7f800001 && decoded <= 0x7fffffff) ||
                   (decoded >= 0xff800001))) decoded = FLOAT_NAN;
    memcpy(dst, &decoded, sizeof(UA_Float));
#else
    if(decoded == 0) *dst = 0.0f;
    else if(decoded == FLOAT_NEG_ZERO) *dst = -0.0f;
    else if(decoded == FLOAT_INF) *dst = INFINITY;
    else if(decoded == FLOAT_NEG_INF) *dst = -INFINITY;
    else if((decoded >= 0x7f800001 && decoded <= 0x7fffffff) ||
       (decoded >= 0xff800001)) *dst = NAN;
    else *dst = (UA_Float)unpack754(decoded, 32, 8);
#endif
    return UA_STATUSCODE_GOOD;
}

/* Double */
#define DOUBLE_NAN 0xfff8000000000000L
#define DOUBLE_INF 0x7ff0000000000000L
#define DOUBLE_NEG_INF 0xfff0000000000000L
#define DOUBLE_NEG_ZERO 0x8000000000000000L

FUNC_ENCODE_BINARY(Double) {
    const UA_Double *src = (const UA_Double*)_src;
    UA_Double d = *src;
    u64 encoded;
    /* cppcheck-suppress duplicateExpression */
    if(UA_UNLIKELY(d != d)) encoded = DOUBLE_NAN; /* quiet NAN*/
#ifndef UA_SLOW_IEEE754
    else memcpy(&encoded, &d, sizeof(UA_Double));
#else
    else if(d == 0.0) encoded = signbit(d) ? DOUBLE_NEG_ZERO : 0;
    else if(d/d != d/d) encoded = d > 0 ? DOUBLE_INF : DOUBLE_NEG_INF;
    else encoded = pack754(d, 64, 11);
 #endif
    return ENCODE_DIRECT(&encoded, UInt64);
}

FUNC_DECODE_BINARY(Double) {
    UA_Double *dst = (UA_Double*)_dst;
    u64 decoded;
    status ret = DECODE_DIRECT(&decoded, UInt64);
    UA_CHECK_STATUS(ret, return ret);
#ifndef UA_SLOW_IEEE754
    if(UA_UNLIKELY((decoded >= 0x7ff0000000000001L && decoded <= 0x7fffffffffffffffL) ||
                   (decoded >= 0xfff0000000000001L))) decoded = DOUBLE_NAN;
    memcpy(dst, &decoded, sizeof(UA_Double));
#else
    if(decoded == 0) *dst = 0.0;
    else if(decoded == DOUBLE_NEG_ZERO) *dst = -0.0;
    else if(decoded == DOUBLE_INF) *dst = INFINITY;
    else if(decoded == DOUBLE_NEG_INF) *dst = -INFINITY;
    else if((decoded >= 0x7ff0000000000001L && decoded <= 0x7fffffffffffffffL) ||
       (decoded >= 0xfff0000000000001L)) *dst = NAN;
    else *dst = (UA_Double)unpack754(decoded, 64, 11);
#endif
    return UA_STATUSCODE_GOOD;
}

/******************/
/* Array Handling */
/******************/

static status
Array_encodeBinaryOverlayable(Ctx *ctx, uintptr_t ptr, size_t memSize) {
    /* CalcSize only */
    if(ctx->end == NULL) {
        ctx->pos += memSize;
        return UA_STATUSCODE_GOOD;
    }

    /* Loop as long as more elements remain than fit into the chunk */
    while(ctx->end < ctx->pos + memSize) {
        size_t possible = ((uintptr_t)ctx->end - (uintptr_t)ctx->pos);
        memcpy(ctx->pos, (void*)ptr, possible);
        ctx->pos += possible;
        ptr += possible;
        status ret = exchangeBuffer(ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
        memSize -= possible;
    }

    /* Encode the remaining elements */
    memcpy(ctx->pos, (void*)ptr, memSize);
    ctx->pos += memSize;
    return UA_STATUSCODE_GOOD;
}

static status
Array_encodeBinaryComplex(Ctx *ctx, uintptr_t ptr, size_t length,
                          const UA_DataType *type) {
    /* Encode every element */
    for(size_t i = 0; i < length; ++i) {
        status ret = encodeWithExchangeBuffer(ctx, (const void*)ptr, type);
        ptr += type->memSize;
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret); /* Unrecoverable fail */
    }
    return UA_STATUSCODE_GOOD;
}

static status
Array_encodeBinary(Ctx *ctx, const void *src, size_t length, const UA_DataType *type) {
    /* Check and convert the array length to int32 */
    i32 signed_length = -1;
    if(length > UA_INT32_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(length > 0)
        signed_length = (i32)length;
    else if(src >= UA_EMPTY_ARRAY_SENTINEL) /* src != NULL */
        signed_length = 0;

    /* Encode the array length */
    status ret = encodeWithExchangeBuffer(ctx, &signed_length, &UA_TYPES[UA_TYPES_INT32]);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the content */
    if(length > 0) {
        if(type->overlayable)
            ret = Array_encodeBinaryOverlayable(ctx, (uintptr_t)src, length * type->memSize);
        else
            ret = Array_encodeBinaryComplex(ctx, (uintptr_t)src, length, type);
    }
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

static status
Array_decodeBinary(Ctx *ctx, void *UA_RESTRICT *UA_RESTRICT dst,
                   size_t *out_length, const UA_DataType *type) {
    /* Decode the length */
    i32 signed_length;
    status ret = DECODE_DIRECT(&signed_length, UInt32); /* Int32 */
    UA_CHECK_STATUS(ret, return ret);

    /* Return early for empty arrays */
    if(signed_length <= 0) {
        *out_length = 0;
        if(signed_length < 0)
            *dst = NULL;
        else
            *dst = UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }

    /* Filter out arrays that can obviously not be decoded, because the message
     * is too small for the array length. This prevents the allocation of very
     * long arrays for bogus messages.
     *
     * The worst known case (so far) is UA_DataValue. It has
     * sizeof(UA_DataValue) == 80 and an empty DataValue is encoded with just
     * one byte. We use 128 as the smallest power of 2 larger than 80. */
    size_t length = (size_t)signed_length;
    size_t remaining = (size_t)(ctx->end - ctx->pos);
    UA_CHECK(length / 128 <= remaining / type->memSize,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Allocate memory */
    *dst = ctxCalloc(ctx, length, type->memSize);
    UA_CHECK_MEM(*dst, return UA_STATUSCODE_BADOUTOFMEMORY);

    if(type->overlayable) {
        /* memcpy overlayable array */
        if(ctx->pos + (type->memSize * length) > ctx->end){
            ctxFree(ctx, *dst);
            *dst = NULL;
            return UA_STATUSCODE_BADDECODINGERROR;
        }
        memcpy(*dst, ctx->pos, type->memSize * length);
        ctx->pos += type->memSize * length;
    } else {
        /* Decode array members */
        uintptr_t ptr = (uintptr_t)*dst;
        for(size_t i = 0; i < length; ++i) {
            ret = decodeBinaryJumpTable[type->typeKind](ctx, (void*)ptr, type);
            if(ret != UA_STATUSCODE_GOOD) {
                if(!ctx->opts.calloc) {
                    /* +1 because last element is also already initialized */
                    UA_Array_delete(*dst, i + 1, type);
                }
                *dst = NULL;
                return ret;
            }
            ptr += type->memSize;
        }
    }
    *out_length = length;
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* Builtin Types */
/*****************/

FUNC_ENCODE_BINARY(String) {
    const UA_String *src = (const UA_String*)_src;
    return Array_encodeBinary(ctx, src->data, src->length, &UA_TYPES[UA_TYPES_BYTE]);
}

FUNC_DECODE_BINARY(String) {
    UA_String *dst = (UA_String*)_dst;
    return Array_decodeBinary(ctx, (void**)&dst->data, &dst->length, &UA_TYPES[UA_TYPES_BYTE]);
}

/* Guid */
FUNC_ENCODE_BINARY(Guid) {
    const UA_Guid *src = (const UA_Guid*)_src;
    status ret = UA_STATUSCODE_GOOD;
    ret |= ENCODE_DIRECT(&src->data1, UInt32);
    ret |= ENCODE_DIRECT(&src->data2, UInt16);
    ret |= ENCODE_DIRECT(&src->data3, UInt16);
    IF_CHECK_BUFSIZE(ctx->pos + (8*sizeof(u8)) <= ctx->end) {
        memcpy(ctx->pos, src->data4, 8*sizeof(u8));
    }
    ctx->pos += 8;
    return ret;
}

FUNC_DECODE_BINARY(Guid) {
    UA_Guid *dst = (UA_Guid*)_dst;
    status ret = UA_STATUSCODE_GOOD;
    ret |= DECODE_DIRECT(&dst->data1, UInt32);
    ret |= DECODE_DIRECT(&dst->data2, UInt16);
    ret |= DECODE_DIRECT(&dst->data3, UInt16);
    UA_CHECK(ctx->pos + (8*sizeof(u8)) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
    memcpy(dst->data4, ctx->pos, 8*sizeof(u8));
    ctx->pos += 8;
    return ret;
}

/* NodeId */
#define UA_NODEIDTYPE_NUMERIC_TWOBYTE 0u
#define UA_NODEIDTYPE_NUMERIC_FOURBYTE 1u
#define UA_NODEIDTYPE_NUMERIC_COMPLETE 2u

#define UA_EXPANDEDNODEID_SERVERINDEX_FLAG 0x40u
#define UA_EXPANDEDNODEID_NAMESPACEURI_FLAG 0x80u

/* For ExpandedNodeId, we prefill the encoding mask. */
static status
NodeId_encodeBinaryWithEncodingMask(Ctx *ctx, UA_NodeId const *src, u8 encoding) {
    status ret = UA_STATUSCODE_GOOD;

    /* Mapping of the namespace index */
    UA_UInt16 nsIndex = src->namespaceIndex;
    if(ctx->opts.namespaceMapping)
        nsIndex = UA_NamespaceMapping_local2Remote(ctx->opts.namespaceMapping,
                                                   nsIndex);

    switch(src->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        if(src->identifier.numeric > UA_UINT16_MAX || nsIndex > UA_BYTE_MAX) {
            encoding |= UA_NODEIDTYPE_NUMERIC_COMPLETE;
            ret |= ENCODE_DIRECT(&encoding, Byte);
            ret |= ENCODE_DIRECT(&nsIndex, UInt16);
            ret |= ENCODE_DIRECT(&src->identifier.numeric, UInt32);
        } else if(src->identifier.numeric > UA_BYTE_MAX || nsIndex > 0) {
            encoding |= UA_NODEIDTYPE_NUMERIC_FOURBYTE;
            ret |= ENCODE_DIRECT(&encoding, Byte);
            u8 nsindex8 = (u8)nsIndex;
            ret |= ENCODE_DIRECT(&nsindex8, Byte);
            u16 identifier16 = (u16)src->identifier.numeric;
            ret |= ENCODE_DIRECT(&identifier16, UInt16);
        } else {
            encoding |= UA_NODEIDTYPE_NUMERIC_TWOBYTE;
            ret |= ENCODE_DIRECT(&encoding, Byte);
            u8 identifier8 = (u8)src->identifier.numeric;
            ret |= ENCODE_DIRECT(&identifier8, Byte);
        }
        break;
    case UA_NODEIDTYPE_STRING:
        encoding |= (u8)UA_NODEIDTYPE_STRING;
        ret |= ENCODE_DIRECT(&encoding, Byte);
        ret |= ENCODE_DIRECT(&nsIndex, UInt16);
        UA_CHECK_STATUS(ret, return ret);
        /* Can exchange the buffer */
        ret = ENCODE_DIRECT(&src->identifier.string, String);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        break;
    case UA_NODEIDTYPE_GUID:
        encoding |= (u8)UA_NODEIDTYPE_GUID;
        ret |= ENCODE_DIRECT(&encoding, Byte);
        ret |= ENCODE_DIRECT(&nsIndex, UInt16);
        ret |= ENCODE_DIRECT(&src->identifier.guid, Guid);
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        encoding |= (u8)UA_NODEIDTYPE_BYTESTRING;
        ret |= ENCODE_DIRECT(&encoding, Byte);
        ret |= ENCODE_DIRECT(&nsIndex, UInt16);
        UA_CHECK_STATUS(ret, return ret);
        /* Can exchange the buffer */
        ret = ENCODE_DIRECT(&src->identifier.byteString, String); /* ByteString */
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        break;
    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return ret;
}

FUNC_ENCODE_BINARY(NodeId) {
    const UA_NodeId *src = (const UA_NodeId*)_src;
    return NodeId_encodeBinaryWithEncodingMask(ctx, src, 0);
}

FUNC_DECODE_BINARY(NodeId) {
    UA_NodeId *dst = (UA_NodeId*)_dst;
    u8 dstByte = 0, encodingByte = 0;
    u16 dstUInt16 = 0;

    /* Decode the encoding bitfield */
    status ret = DECODE_DIRECT(&encodingByte, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Filter out the bits used only for ExpandedNodeIds */
    encodingByte &= (u8)~(u8)(UA_EXPANDEDNODEID_SERVERINDEX_FLAG |
                              UA_EXPANDEDNODEID_NAMESPACEURI_FLAG);

    /* Decode the namespace and identifier */
    switch(encodingByte) {
    case UA_NODEIDTYPE_NUMERIC_TWOBYTE:
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        ret = DECODE_DIRECT(&dstByte, Byte);
        dst->identifier.numeric = dstByte;
        dst->namespaceIndex = 0;
        break;
    case UA_NODEIDTYPE_NUMERIC_FOURBYTE:
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        ret |= DECODE_DIRECT(&dstByte, Byte);
        dst->namespaceIndex = dstByte;
        ret |= DECODE_DIRECT(&dstUInt16, UInt16);
        dst->identifier.numeric = dstUInt16;
        break;
    case UA_NODEIDTYPE_NUMERIC_COMPLETE:
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.numeric, UInt32);
        break;
    case UA_NODEIDTYPE_STRING:
        dst->identifierType = UA_NODEIDTYPE_STRING;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.string, String);
        break;
    case UA_NODEIDTYPE_GUID:
        dst->identifierType = UA_NODEIDTYPE_GUID;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.guid, Guid);
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        dst->identifierType = UA_NODEIDTYPE_BYTESTRING;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.byteString, String); /* ByteString */
        break;
    default:
        ret |= UA_STATUSCODE_BADINTERNALERROR;
        break;
    }

    /* Mapping of the namespace index */
    if(ctx->opts.namespaceMapping)
        dst->namespaceIndex =
            UA_NamespaceMapping_remote2Local(ctx->opts.namespaceMapping,
                                             dst->namespaceIndex);

    return ret;
}

/* ExpandedNodeId */
FUNC_ENCODE_BINARY(ExpandedNodeId) {
    const UA_ExpandedNodeId *src = (const UA_ExpandedNodeId*)_src;

    /* Set up the encoding mask */
    u8 encoding = 0;
    if((void*)src->namespaceUri.data > UA_EMPTY_ARRAY_SENTINEL)
        encoding |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG;
    if(src->serverIndex > 0)
        encoding |= UA_EXPANDEDNODEID_SERVERINDEX_FLAG;

    /* Encode the NodeId. Can exchange the buffer. */
    status ret = NodeId_encodeBinaryWithEncodingMask(ctx, &src->nodeId, encoding);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the namespace. Internally uses encodeWithExchangeBuffer
     * everywhere. So it will never return
     * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */
    if((void*)src->namespaceUri.data > UA_EMPTY_ARRAY_SENTINEL) {
        ret = ENCODE_DIRECT(&src->namespaceUri, String);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Encode the serverIndex */
    if(src->serverIndex > 0)
        ret = encodeWithExchangeBuffer(ctx, &src->serverIndex, &UA_TYPES[UA_TYPES_UINT32]);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

FUNC_DECODE_BINARY(ExpandedNodeId) {
    UA_ExpandedNodeId *dst = (UA_ExpandedNodeId*)_dst;
    /* Decode the encoding mask */
    UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADDECODINGERROR);
    u8 encoding = *ctx->pos;

    /* Decode the NodeId */
    status ret = DECODE_DIRECT(&dst->nodeId, NodeId);

    /* Decode the NamespaceUri */
    if(encoding & UA_EXPANDEDNODEID_NAMESPACEURI_FLAG) {
        dst->nodeId.namespaceIndex = 0;
        ret |= DECODE_DIRECT(&dst->namespaceUri, String);
        /* Try to resolve the namespace uri to a namespace index */
        if(ctx->opts.namespaceMapping) {
            status foundNsUri =
                UA_NamespaceMapping_uri2Index(ctx->opts.namespaceMapping,
                                              dst->namespaceUri,
                                              &dst->nodeId.namespaceIndex);
            if(foundNsUri == UA_STATUSCODE_GOOD)
                UA_String_clear(&dst->namespaceUri);
        }
    }

    /* Decode the ServerIndex */
    if(encoding & UA_EXPANDEDNODEID_SERVERINDEX_FLAG)
        ret |= DECODE_DIRECT(&dst->serverIndex, UInt32);
    return ret;
}

/* QualifiedName */
FUNC_ENCODE_BINARY(QualifiedName) {
    const UA_QualifiedName *src = (const UA_QualifiedName*)_src;
    status ret = ENCODE_DIRECT(&src->namespaceIndex, UInt16);
    /* Must check here so we can exchange the buffer in the string encoding */
    UA_CHECK_STATUS(ret, return ret);
    ret |= ENCODE_DIRECT(&src->name, String);
    return ret;
}

FUNC_DECODE_BINARY(QualifiedName) {
    UA_QualifiedName *dst = (UA_QualifiedName*)_dst;
    status ret = DECODE_DIRECT(&dst->namespaceIndex, UInt16);
    ret |= DECODE_DIRECT(&dst->name, String);
    return ret;
}

/* LocalizedText */
#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE 0x01u
#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT 0x02u

FUNC_ENCODE_BINARY(LocalizedText) {
    const UA_LocalizedText *src = (const UA_LocalizedText*)_src;

    /* Set up the encoding mask */
    u8 encoding = 0;
    if(src->locale.data)
        encoding |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
    if(src->text.data)
        encoding |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;

    /* Encode the encoding byte */
    status ret = ENCODE_DIRECT(&encoding, Byte);
    /* Must check here so we can exchange the buffer in the string encoding */
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the strings */
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE)
        ret |= ENCODE_DIRECT(&src->locale, String);
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT)
        ret |= ENCODE_DIRECT(&src->text, String);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

FUNC_DECODE_BINARY(LocalizedText) {
    UA_LocalizedText *dst = (UA_LocalizedText*)_dst;
    /* Decode the encoding mask */
    u8 encoding = 0;
    status ret = DECODE_DIRECT(&encoding, Byte);

    /* Decode the content */
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE)
        ret |= DECODE_DIRECT(&dst->locale, String);
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT)
        ret |= DECODE_DIRECT(&dst->text, String);
    return ret;
}

/* The binary encoding has a different nodeid from the data type. So it is not
 * possible to reuse UA_findDataType */
static const UA_DataType *
UA_findDataTypeByBinaryInternal(Ctx *ctx, const UA_NodeId *typeId) {
    /* Always look in the built-in types first. Assume that only numeric
     * identifiers are used for the builtin types. (They may contain data types
     * from all namespaces though.) */
    if(typeId->identifierType == UA_NODEIDTYPE_NUMERIC) {
        for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
            if(UA_TYPES[i].binaryEncodingId.identifier.numeric == typeId->identifier.numeric &&
               UA_TYPES[i].binaryEncodingId.namespaceIndex == typeId->namespaceIndex)
                return &UA_TYPES[i];
        }
    }

    const UA_DataTypeArray *customTypes = ctx->opts.customTypes;
    while(customTypes) {
        for(size_t i = 0; i < customTypes->typesSize; ++i) {
            if(UA_NodeId_equal(typeId, &customTypes->types[i].binaryEncodingId))
                return &customTypes->types[i];
        }
        customTypes = customTypes->next;
    }

    return NULL;
}

const UA_DataType *
UA_findDataTypeByBinary(const UA_NodeId *typeId) {
    Ctx ctx;
    ctx.opts.customTypes = NULL;
    return UA_findDataTypeByBinaryInternal(&ctx, typeId);
}

/* ExtensionObject */
FUNC_ENCODE_BINARY(ExtensionObject) {
    const UA_ExtensionObject *src = (const UA_ExtensionObject*)_src;
    u8 encoding = (u8)src->encoding;

    /* No content or already encoded content. */
    if(encoding <= UA_EXTENSIONOBJECT_ENCODED_XML) {
        /* Can exchange the buffer */
        status ret = ENCODE_DIRECT(&src->content.encoded.typeId, NodeId);
        UA_CHECK_STATUS(ret, return ret);
        ret = encodeWithExchangeBuffer(ctx, &encoding, &UA_TYPES[UA_TYPES_BYTE]);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
        switch(src->encoding) {
        case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
            break;
        case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
        case UA_EXTENSIONOBJECT_ENCODED_XML:
            /* ByteString in disguise. Array encoding can exchange the buffer */
            ret = ENCODE_DIRECT(&src->content.encoded.body, String);
            break;
        default:
            ret = UA_STATUSCODE_BADINTERNALERROR;
        }
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        return ret;
    }

    /* Cannot encode with no data or no type description */
    if(!src->content.decoded.type || !src->content.decoded.data)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Write the NodeId for the binary encoded type. This could perform a buffer
     * exchange, but can also return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */
    status ret = ENCODE_DIRECT(&src->content.decoded.type->binaryEncodingId, NodeId);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the encoding byte */
    encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
    ret = encodeWithExchangeBuffer(ctx, &encoding, &UA_TYPES[UA_TYPES_BYTE]);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    UA_CHECK_STATUS(ret, return ret);

    const UA_DataType *contentType = src->content.decoded.type;

    /* Compute the content length. But only if we are not already in the
     * calcSizeBinary mode. This is avoids recursive cycles.*/
    i32 signed_len = 0;
    if(ctx->end != NULL) {
        UA_EncodeBinaryOptions opts;
        memset(&opts, 0, sizeof(UA_EncodeBinaryOptions));
        opts.namespaceMapping = ctx->opts.namespaceMapping;
        size_t len = UA_calcSizeBinary(src->content.decoded.data, contentType, &opts);
        UA_CHECK(len <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR);
        signed_len = (i32)len;
    }
    ret = encodeWithExchangeBuffer(ctx, &signed_len, &UA_TYPES[UA_TYPES_INT32]);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the content */
    ret = encodeWithExchangeBuffer(ctx, src->content.decoded.data, contentType);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

static status
ExtensionObject_decodeBinaryContent(Ctx *ctx, UA_ExtensionObject *dst,
                                    const UA_NodeId *typeId) {
    /* Lookup the datatype */
    const UA_DataType *type = UA_findDataTypeByBinaryInternal(ctx, typeId);

    /* Unknown type, just take the binary content */
    if(!type) {
        dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
        UA_NodeId_copy(typeId, &dst->content.encoded.typeId);
        return DECODE_DIRECT(&dst->content.encoded.body, String); /* ByteString */
    }

    /* Allocate memory */
    dst->content.decoded.data = ctxCalloc(ctx, 1, type->memSize);
    UA_CHECK_MEM(dst->content.decoded.data, return UA_STATUSCODE_BADOUTOFMEMORY);

    /* Jump over the length field (TODO: check if the decoded length matches) */
    ctx->pos += 4;

    /* Decode */
    dst->encoding = UA_EXTENSIONOBJECT_DECODED;
    dst->content.decoded.type = type;
    return decodeBinaryJumpTable[type->typeKind](ctx, dst->content.decoded.data, type);
}

FUNC_DECODE_BINARY(ExtensionObject) {
    UA_ExtensionObject *dst = (UA_ExtensionObject*)_dst;
    u8 encoding = 0;
    UA_NodeId binTypeId;
    UA_NodeId_init(&binTypeId);

    status ret = UA_STATUSCODE_GOOD;
    ret |= DECODE_DIRECT(&binTypeId, NodeId);
    ret |= DECODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, ctxClearNodeId(ctx, &binTypeId); return ret);

    switch(encoding) {
    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
        ret = ExtensionObject_decodeBinaryContent(ctx, dst, &binTypeId);
        ctxClearNodeId(ctx, &binTypeId);
        break;
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
        dst->encoding = (UA_ExtensionObjectEncoding)encoding;
        dst->content.encoded.typeId = binTypeId; /* move to dst */
        dst->content.encoded.body = UA_BYTESTRING_NULL;
        break;
    case UA_EXTENSIONOBJECT_ENCODED_XML:
        dst->encoding = (UA_ExtensionObjectEncoding)encoding;
        dst->content.encoded.typeId = binTypeId; /* move to dst */
        ret = DECODE_DIRECT(&dst->content.encoded.body, String); /* ByteString */
        UA_CHECK_STATUS(ret, ctxClearNodeId(ctx, &dst->content.encoded.typeId));
        break;
    default:
        ctxClearNodeId(ctx, &binTypeId);
        ret = UA_STATUSCODE_BADDECODINGERROR;
        break;
    }

    return ret;
}

/* Variant */

static status
Variant_encodeBinaryWrapExtensionObject(Ctx *ctx, const UA_Variant *src,
                                        const UA_Boolean isArray) {
    size_t length = 1; /* Default to 1 for a scalar. */

    /* Encode the array length if required */
    status ret = UA_STATUSCODE_GOOD;
    if(isArray) {
        UA_CHECK(src->arrayLength <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR);
        length = src->arrayLength;

        i32 encodedLength = (i32)src->arrayLength;
        ret = encodeWithExchangeBuffer(ctx, &encodedLength, &UA_TYPES[UA_TYPES_INT32]);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Set up the ExtensionObject */
    UA_ExtensionObject eo;
    UA_ExtensionObject_init(&eo);
    eo.encoding = UA_EXTENSIONOBJECT_DECODED;
    eo.content.decoded.type = src->type;
    const u16 memSize = src->type->memSize;
    uintptr_t ptr = (uintptr_t)src->data;

    /* Iterate over the array */
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) {
        eo.content.decoded.data = (void*)ptr;
        ret = encodeWithExchangeBuffer(ctx, &eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        ptr += memSize;
    }
    return ret;
}

enum UA_VARIANT_ENCODINGMASKTYPE {
    UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3Fu,        /* bits 0:5 */
    UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS = (u8)(0x01u << 6u), /* bit 6 */
    UA_VARIANT_ENCODINGMASKTYPE_ARRAY = (u8)(0x01u << 7u)  /* bit 7 */
};

FUNC_ENCODE_BINARY(Variant) {
    const UA_Variant *src = (const UA_Variant*)_src;

    /* Quit early for the empty variant */
    u8 encoding = 0;
    if(!src->type)
        return ENCODE_DIRECT(&encoding, Byte);

    /* Set the content type in the encoding mask */
    const UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    const UA_Boolean isEnum = (src->type->typeKind == UA_DATATYPEKIND_ENUM);
    if(isBuiltin)
        encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(src->type->typeKind + 1u)));
    else if(isEnum)
        encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(UA_TYPES_INT32 + 1u)));
    else
        encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(UA_TYPES_EXTENSIONOBJECT + 1u)));

    /* Set the array type in the encoding mask */
    const UA_Boolean isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL;
    const UA_Boolean hasDimensions = isArray && src->arrayDimensionsSize > 0;
    if(isArray) {
        encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
        if(hasDimensions) {
            encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS;
            size_t totalRequiredSize = 1;
            for(size_t i = 0; i < src->arrayDimensionsSize; ++i)
                totalRequiredSize *= src->arrayDimensions[i];
            if(totalRequiredSize != src->arrayLength) return UA_STATUSCODE_BADENCODINGERROR;
        }
    }

    /* Encode the encoding byte */
    status ret = ENCODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the content. This can exchange the buffer. */
    if(!isBuiltin && !isEnum) {
        /* This could return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. But we
         * have not exchanged the buffer so far. */
        ret = Variant_encodeBinaryWrapExtensionObject(ctx, src, isArray);
    } else if(!isArray) {
        ret = encodeWithExchangeBuffer(ctx, src->data, src->type);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    } else {
        ret = Array_encodeBinary(ctx, src->data, src->arrayLength, src->type);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    }
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the array dimensions */
    if(hasDimensions && ret == UA_STATUSCODE_GOOD)
        ret = Array_encodeBinary(ctx, src->arrayDimensions, src->arrayDimensionsSize,
                                 &UA_TYPES[UA_TYPES_INT32]);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

static status
Variant_decodeBinaryUnwrapExtensionObject(Ctx *ctx, UA_Variant *dst) {
    /* Save the position in the ByteString. If unwrapping is not possible, start
     * from here to decode a normal ExtensionObject. */
    u8 *old_pos = ctx->pos;

    /* Decode the DataType */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    status ret = DECODE_DIRECT(&typeId, NodeId);
    UA_CHECK_STATUS(ret, return ret);

    /* Decode the EncodingByte */
    u8 encoding;
    ret = DECODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, ctxClearNodeId(ctx, &typeId); return ret);

    /* Search for the datatype. Default to ExtensionObject. */
    if(encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING &&
       (dst->type = UA_findDataTypeByBinaryInternal(ctx, &typeId)) != NULL) {
        /* Jump over the length field (TODO: check if length matches) */
        ctx->pos += 4;
    } else {
        /* Reset and decode as ExtensionObject */
        dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
        ctx->pos = old_pos;
    }
    ctxClearNodeId(ctx, &typeId);

    /* Allocate memory */
    dst->data = ctxCalloc(ctx, 1, dst->type->memSize);
    UA_CHECK_MEM(dst->data, return UA_STATUSCODE_BADOUTOFMEMORY);

    /* Decode the content */
    return decodeBinaryJumpTable[dst->type->typeKind](ctx, dst->data, dst->type);
}

/* Unwraps all ExtensionObjects in an array if they have the same type.
 * For that we check whether all ExtensionObjects have the same header. */
static status
Variant_decodeBinaryUnwrapExtensionObjectArray(Ctx *ctx, void *UA_RESTRICT *UA_RESTRICT dst,
                                               size_t *out_length, const UA_DataType **type) {
    u8 *orig_pos = ctx->pos;

    /* Decode the length */
    i32 signed_length;
    status ret = DECODE_DIRECT(&signed_length, UInt32); /* Int32 */
    UA_CHECK_STATUS(ret, return ret);

    /* Return early for empty arrays */
    if(signed_length <= 0) {
        *out_length = 0;
        if(signed_length < 0)
            *dst = NULL;
        else
            *dst = UA_EMPTY_ARRAY_SENTINEL;
        /* The *type field stays an ExtensionObject, as we did not decode any
         * member who's type is known. */
        return UA_STATUSCODE_GOOD;
    }

    /* Protect against memory exhaustion by unrealistic array lengths. An
     * ExtensionObject is at least 4 byte long (3 byte NodeId + 1 Byte encoding
     * field). */
    size_t length = (size_t)signed_length;
    UA_CHECK(ctx->pos + ((4 * length) / 32) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Decode the type NodeId of the first member */
    UA_NodeId binTypeId;
    UA_NodeId_init(&binTypeId);
    ret |= DECODE_DIRECT(&binTypeId, NodeId);
    UA_CHECK_STATUS(ret, return ret);

    /* Lookup the data type */
    const UA_DataType *contentType = UA_findDataTypeByBinaryInternal(ctx, &binTypeId);
    ctxClearNodeId(ctx, &binTypeId);
    if(!contentType) {
        /* DataType unknown, decode as ExtensionObject array */
        ctx->pos = orig_pos;
        return Array_decodeBinary(ctx, dst, out_length, *type);
    }

    /* Check that the encoding is binary */
    u8 encoding = 0;
    ret |= DECODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, return ret);
    if(encoding != UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
        /* Encoding format is not automatically decoded, decode as
         * ExtensionObject array */
        ctx->pos = orig_pos;
        return Array_decodeBinary(ctx, dst, out_length, *type);
    }

    /* Compare the header of all array members if the array can be unwrapped */
    UA_ByteString header = {(uintptr_t)ctx->pos - (uintptr_t)orig_pos - 4, &orig_pos[4]};
    UA_ByteString compare_header = header;
    ctx->pos = &orig_pos[4];

    for(size_t i = 0; i < length; i++) {
        compare_header.data = ctx->pos;
        UA_CHECK(compare_header.data + compare_header.length <= ctx->end,
                 return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        if(!UA_ByteString_equal(&header, &compare_header)) {
            /* Different member types, decode as ExtensionObject array */
            ctx->pos = orig_pos;
            return Array_decodeBinary(ctx, dst, out_length, *type);
        }

        /* Decode the length field and jump to the next element */
        ctx->pos += header.length;
        u32 member_length = 0;
        ret = DECODE_DIRECT(&member_length, UInt32);
        UA_CHECK_STATUS(ret, return ret);
        ctx->pos += member_length;
    }

    /* Allocate memory for the unwrapped members */
    *dst = ctxCalloc(ctx, length, contentType->memSize);
    UA_CHECK_MEM(*dst, return UA_STATUSCODE_BADOUTOFMEMORY);
    *out_length = length;
    *type = contentType;

    /* Decode unwrapped members */
    uintptr_t array_pos = (uintptr_t)*dst;
    ctx->pos = &orig_pos[4];
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; i++) {
        ctx->pos += header.length + 4; /* Jump over the header and length field */
        ret = decodeBinaryJumpTable[contentType->typeKind]
            (ctx, (void*)array_pos, contentType);
        array_pos += contentType->memSize;
    }
    return ret;
}

/* The resulting variant always has the storagetype UA_VARIANT_DATA. */
FUNC_DECODE_BINARY(Variant) {
    UA_Variant *dst = (UA_Variant*)_dst;

    /* Decode the encoding byte */
    u8 encodingByte;
    status ret = DECODE_DIRECT(&encodingByte, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Return early for an empty variant (was already _inited) */
    if(encodingByte == 0)
        return UA_STATUSCODE_GOOD;

    /* Does the variant contain an array? */
    const UA_Boolean isArray = (encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_ARRAY) > 0;

    /* Get the datatype of the content. The type must be a builtin data type.
     * All not-builtin types are wrapped in an ExtensionObject. The "type kind"
     * for types up to DiagnsticInfo equals to the index in the encoding
     * byte. */
    size_t typeKind = (size_t)((encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1);
    UA_CHECK(typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO, return UA_STATUSCODE_BADDECODINGERROR);

    /* A variant cannot contain a variant. But it can contain an array of
     * variants */
    UA_CHECK(typeKind != UA_DATATYPEKIND_VARIANT || isArray,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Decode the content */
    dst->type = &UA_TYPES[typeKind];
    if(!isArray) {
        /* Decode scalar */
        if(typeKind != UA_DATATYPEKIND_EXTENSIONOBJECT) {
            dst->data = ctxCalloc(ctx, 2, dst->type->memSize);
            UA_CHECK_MEM(dst->data, ctx->depth--; return UA_STATUSCODE_BADOUTOFMEMORY);
            ret = decodeBinaryJumpTable[typeKind](ctx, dst->data, dst->type);
        } else {
            ret = Variant_decodeBinaryUnwrapExtensionObject(ctx, dst);
        }
    } else {
        /* Decode array */
        if(typeKind != UA_DATATYPEKIND_EXTENSIONOBJECT) {
            ret = Array_decodeBinary(ctx, &dst->data, &dst->arrayLength, dst->type);
        } else {
            ret = Variant_decodeBinaryUnwrapExtensionObjectArray(ctx, &dst->data,
                                                                 &dst->arrayLength, &dst->type);
        }

        /* Decode array dimensions */
        if((encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS) > 0) {
            ret |= Array_decodeBinary(ctx, (void **)&dst->arrayDimensions,
                                      &dst->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
            /* Validate array length against array dimensions */
            size_t totalSize = 1;
            for(size_t i = 0; i < dst->arrayDimensionsSize; ++i) {
                if(dst->arrayDimensions[i] == 0)
                    ret = UA_STATUSCODE_BADDECODINGERROR;
                totalSize *= dst->arrayDimensions[i];
            }
            UA_CHECK(totalSize == dst->arrayLength, ret = UA_STATUSCODE_BADDECODINGERROR);
        }
    }

    ctx->depth--;
    return ret;
}

/* DataValue */
FUNC_ENCODE_BINARY(DataValue) {
    const UA_DataValue *src = (const UA_DataValue*)_src;

    /* Set up the encoding mask */
    u8 encodingMask = src->hasValue;
    encodingMask |= (u8)(src->hasStatus << 1u);
    encodingMask |= (u8)(src->hasSourceTimestamp << 2u);
    encodingMask |= (u8)(src->hasServerTimestamp << 3u);
    encodingMask |= (u8)(src->hasSourcePicoseconds << 4u);
    encodingMask |= (u8)(src->hasServerPicoseconds << 5u);

    /* Encode the encoding byte */
    status ret = ENCODE_DIRECT(&encodingMask, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the variant. */
    if(src->hasValue) {
        ret = ENCODE_DIRECT(&src->value, Variant);
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
    }

    if(src->hasStatus)
        ret |= encodeWithExchangeBuffer(ctx, &src->status, &UA_TYPES[UA_TYPES_STATUSCODE]);
    if(src->hasSourceTimestamp)
        ret |= encodeWithExchangeBuffer(ctx, &src->sourceTimestamp, &UA_TYPES[UA_TYPES_DATETIME]);
    if(src->hasSourcePicoseconds)
        ret |= encodeWithExchangeBuffer(ctx, &src->sourcePicoseconds, &UA_TYPES[UA_TYPES_UINT16]);
    if(src->hasServerTimestamp)
        ret |= encodeWithExchangeBuffer(ctx, &src->serverTimestamp, &UA_TYPES[UA_TYPES_DATETIME]);
    if(src->hasServerPicoseconds)
        ret |= encodeWithExchangeBuffer(ctx, &src->serverPicoseconds, &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

#define MAX_PICO_SECONDS 9999

FUNC_DECODE_BINARY(DataValue) {
    UA_DataValue *dst = (UA_DataValue*)_dst;

    /* Decode the encoding mask */
    u8 encodingMask;
    status ret = DECODE_DIRECT(&encodingMask, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Decode the content */
    if(encodingMask & 0x01u) {
        dst->hasValue = true;
        ret |= DECODE_DIRECT(&dst->value, Variant);
    }
    if(encodingMask & 0x02u) {
        dst->hasStatus = true;
        ret |= DECODE_DIRECT(&dst->status, UInt32); /* StatusCode */
    }
    if(encodingMask & 0x04u) {
        dst->hasSourceTimestamp = true;
        ret |= DECODE_DIRECT(&dst->sourceTimestamp, UInt64); /* DateTime */
    }
    if(encodingMask & 0x10u) {
        dst->hasSourcePicoseconds = true;
        ret |= DECODE_DIRECT(&dst->sourcePicoseconds, UInt16);
        if(dst->sourcePicoseconds > MAX_PICO_SECONDS)
            dst->sourcePicoseconds = MAX_PICO_SECONDS;
    }
    if(encodingMask & 0x08u) {
        dst->hasServerTimestamp = true;
        ret |= DECODE_DIRECT(&dst->serverTimestamp, UInt64); /* DateTime */
    }
    if(encodingMask & 0x20u) {
        dst->hasServerPicoseconds = true;
        ret |= DECODE_DIRECT(&dst->serverPicoseconds, UInt16);
        if(dst->serverPicoseconds > MAX_PICO_SECONDS)
            dst->serverPicoseconds = MAX_PICO_SECONDS;
    }

    ctx->depth--;
    return ret;
}

/* DiagnosticInfo */
FUNC_ENCODE_BINARY(DiagnosticInfo) {
    const UA_DiagnosticInfo *src = (const UA_DiagnosticInfo*)_src;

    /* Set up the encoding mask */
    u8 encodingMask = src->hasSymbolicId;
    encodingMask |= (u8)(src->hasNamespaceUri << 1u);
    encodingMask |= (u8)(src->hasLocalizedText << 2u);
    encodingMask |= (u8)(src->hasLocale << 3u);
    encodingMask |= (u8)(src->hasAdditionalInfo << 4u);
    encodingMask |= (u8)(src->hasInnerStatusCode << 5u);
    encodingMask |= (u8)(src->hasInnerDiagnosticInfo << 6u);

    /* Encode the numeric content */
    status ret = ENCODE_DIRECT(&encodingMask, Byte);
    if(src->hasSymbolicId)
        ret |= ENCODE_DIRECT(&src->symbolicId, UInt32); /* Int32 */
    if(src->hasNamespaceUri)
        ret |= ENCODE_DIRECT(&src->namespaceUri, UInt32); /* Int32 */
    if(src->hasLocale)
        ret |= ENCODE_DIRECT(&src->locale, UInt32); /* Int32 */
    if(src->hasLocalizedText)
        ret |= ENCODE_DIRECT(&src->localizedText, UInt32); /* Int32 */
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Encode the additional info. Can exchange the buffer. */
    if(src->hasAdditionalInfo) {
        ret = ENCODE_DIRECT(&src->additionalInfo, String);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Encode the inner status code */
    if(src->hasInnerStatusCode) {
        ret = encodeWithExchangeBuffer(ctx, &src->innerStatusCode, &UA_TYPES[UA_TYPES_UINT32]);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Encode the inner diagnostic info */
    if(src->hasInnerDiagnosticInfo) {
        ret = encodeWithExchangeBuffer(ctx, src->innerDiagnosticInfo,
                                       &UA_TYPES[UA_TYPES_DIAGNOSTICINFO]);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    }

    return ret;
}

FUNC_DECODE_BINARY(DiagnosticInfo) {
    UA_DiagnosticInfo *dst = (UA_DiagnosticInfo*)_dst;

    /* Decode the encoding mask */
    u8 encodingMask;
    status ret = DECODE_DIRECT(&encodingMask, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Decode the content */
    if(encodingMask & 0x01u) {
        dst->hasSymbolicId = true;
        ret |= DECODE_DIRECT(&dst->symbolicId, UInt32); /* Int32 */
    }
    if(encodingMask & 0x02u) {
        dst->hasNamespaceUri = true;
        ret |= DECODE_DIRECT(&dst->namespaceUri, UInt32); /* Int32 */
    }
    if(encodingMask & 0x08u) {
        dst->hasLocale = true;
        ret |= DECODE_DIRECT(&dst->locale, UInt32); /* Int32 */
    }
    if(encodingMask & 0x04u) {
        dst->hasLocalizedText = true;
        ret |= DECODE_DIRECT(&dst->localizedText, UInt32); /* Int32 */
    }
    if(encodingMask & 0x10u) {
        dst->hasAdditionalInfo = true;
        ret |= DECODE_DIRECT(&dst->additionalInfo, String);
    }
    if(encodingMask & 0x20u) {
        dst->hasInnerStatusCode = true;
        ret |= DECODE_DIRECT(&dst->innerStatusCode, UInt32); /* StatusCode */
    }
    if(encodingMask & 0x40u) {
        /* innerDiagnosticInfo is allocated on the heap */
        dst->innerDiagnosticInfo = (UA_DiagnosticInfo*)
            ctxCalloc(ctx, 1, sizeof(UA_DiagnosticInfo));
        UA_CHECK_MEM(dst->innerDiagnosticInfo, return UA_STATUSCODE_BADOUTOFMEMORY);
        dst->hasInnerDiagnosticInfo = true;

        /* Check the recursion limit */
        UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
                 return UA_STATUSCODE_BADENCODINGERROR);

        ctx->depth++;
        ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo);
        ctx->depth--;
    }
    return ret;
}

/********************/
/* Structured Types */
/********************/

static status
encodeBinaryStruct(Ctx *UA_RESTRICT ctx, const void *UA_RESTRICT src,
                   const UA_DataType *type) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Loop over members */
    uintptr_t ptr = (uintptr_t)src;
    status ret = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;

        /* Array. Buffer-exchange is done inside Array_encodeBinary if required. */
        if(m->isArray) {
            const size_t length = *((const size_t*)ptr);
            ptr += sizeof(size_t);
            ret = Array_encodeBinary(ctx, *(void *UA_RESTRICT const *)ptr, length, mt);
            UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
            ptr += sizeof(void*);
            continue;
        }

        /* Scalar */
        ret = encodeWithExchangeBuffer(ctx, (const void*)ptr, mt);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        ptr += mt->memSize;
    }

    ctx->depth--;
    return ret;
}

static status
encodeBinaryStructWithOptFields(Ctx *UA_RESTRICT ctx,
                                const void *UA_RESTRICT src,
                                const UA_DataType *type) {
    /* Check the recursion limit */
    if(ctx->depth > UA_ENCODING_MAX_RECURSION)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;

    /* Creating the encoding mask, marking the available optional fields */
    uintptr_t ptr = (uintptr_t)src;
    size_t optFieldCounter = 0;
    UA_UInt32 encodingMask = 0;
    for(size_t j = 0; j < type->membersSize; ++j) {
        const UA_DataTypeMember *m = &type->members[j];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;
        if(m->isOptional) {
            if(m->isArray)
                ptr += sizeof(size_t);
            if(*(void* const*)ptr != NULL)
                encodingMask |= (UA_UInt32) 1 << optFieldCounter;
            ptr += sizeof(void *);
            optFieldCounter++;
        } else if (m->isArray) {
            ptr += sizeof(size_t);
            ptr += sizeof(void *);
        } else {
            ptr += mt->memSize;
        }
    }

    /* Encode the mask */
    status ret = ENCODE_DIRECT(&encodingMask, UInt32);
    UA_CHECK_STATUS(ret, ctx->depth--; return ret);

    /* Loop over members */
    ptr = (uintptr_t)src;
    for(size_t i = 0, o = 0; i < type->membersSize && UA_LIKELY(ret == UA_STATUSCODE_GOOD); ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;

        if(m->isOptional) {
            if(!(encodingMask & (UA_UInt32) ( (UA_UInt32) 1<<(o++)))) {
                /* Optional and not contained */
                if(m->isArray)
                    ptr += sizeof(size_t);
            } else if(m->isArray) {
                /* Optional Array */
                const size_t length = *((const size_t *) ptr);
                ptr += sizeof(size_t);
                ret = Array_encodeBinary(ctx, *(void *UA_RESTRICT const *) ptr, length, mt);
            } else {
                /* Optional Scalar */
                ret = encodeWithExchangeBuffer(ctx, *(void* const*) ptr, mt);
            }
            ptr += sizeof(void *);
            continue;
        }

        /* Mandatory Array */
        if(m->isArray) {
            const size_t length = *((const size_t *) ptr);
            ptr += sizeof(size_t);
            ret = Array_encodeBinary(ctx, *(void *UA_RESTRICT const *) ptr, length, mt);
            ptr += sizeof(void *);
            continue;
        }

        /* Mandatory Scalar */
        ret = encodeWithExchangeBuffer(ctx, (const void*)ptr, mt);
        ptr += mt->memSize;
    }
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);

    ctx->depth--;
    return ret;
}

static status
encodeBinaryUnion(Ctx *UA_RESTRICT ctx, const void *UA_RESTRICT src,
                  const UA_DataType *type) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Encode the selection */
    const UA_UInt32 selection = *(const UA_UInt32*)src;
    status ret = ENCODE_DIRECT(&selection, UInt32);
    if(UA_UNLIKELY(ret != UA_STATUSCODE_GOOD) || selection == 0) {
        ctx->depth--;
        return ret;
    }

    /* Select the member */
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;

    /* Encode the member */
    uintptr_t ptr = ((uintptr_t)src) + m->padding; /* includes the switchfield length */
    if(!m->isArray) {
        ret = encodeWithExchangeBuffer(ctx, (const void*)ptr, mt);
    } else {
        const size_t length = *((const size_t*)ptr);
        ptr += sizeof(size_t);
        ret = Array_encodeBinary(ctx, *(void *UA_RESTRICT const *)ptr, length, mt);
    }

    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);

    ctx->depth--;
    return ret;
}

static status
encodeBinaryNotImplemented(Ctx *UA_RESTRICT ctx, const void *UA_RESTRICT src,
                           const UA_DataType *type) {
    (void)src, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS] = {
    Boolean_encodeBinary,
    Byte_encodeBinary, /* SByte */
    Byte_encodeBinary,
    UInt16_encodeBinary, /* Int16 */
    UInt16_encodeBinary,
    UInt32_encodeBinary, /* Int32 */
    UInt32_encodeBinary,
    UInt64_encodeBinary, /* Int64 */
    UInt64_encodeBinary,
    Float_encodeBinary,
    Double_encodeBinary,
    String_encodeBinary,
    UInt64_encodeBinary, /* DateTime */
    Guid_encodeBinary,
    String_encodeBinary, /* ByteString */
    String_encodeBinary, /* XmlElement */
    NodeId_encodeBinary,
    ExpandedNodeId_encodeBinary,
    UInt32_encodeBinary, /* StatusCode */
    QualifiedName_encodeBinary,
    LocalizedText_encodeBinary,
    ExtensionObject_encodeBinary,
    DataValue_encodeBinary,
    Variant_encodeBinary,
    DiagnosticInfo_encodeBinary,
    encodeBinaryNotImplemented, /* Decimal */
    UInt32_encodeBinary, /* Enumeration */
    encodeBinaryStruct,
    encodeBinaryStructWithOptFields, /* Structure with Optional Fields */
    encodeBinaryUnion, /* Union */
    encodeBinaryStruct /* BitfieldCluster */
};

status
UA_encodeBinaryInternal(const void *src, const UA_DataType *type,
                        u8 **bufPos, const u8 **bufEnd,
                        UA_EncodeBinaryOptions *options,
                        UA_exchangeEncodeBuffer exchangeCallback,
                        void *exchangeHandle) {
    if(!type || !src)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Set up the context */
    Ctx ctx;
    memset(&ctx, 0, sizeof(Ctx));
    ctx.pos = *bufPos;
    ctx.end = *bufEnd;
    ctx.depth = 0;
    ctx.exchangeBufferCallback = exchangeCallback;
    ctx.exchangeBufferCallbackHandle = exchangeHandle;
    if(options)
        ctx.opts.namespaceMapping = options->namespaceMapping;

    /* Encode */
    status ret = encodeWithExchangeBuffer(&ctx, src, type);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);

    /* Set the new buffer position for the output. Beware that the buffer might
     * have been exchanged internally. */
    *bufPos = ctx.pos;
    *bufEnd = ctx.end;
    return ret;
}

UA_StatusCode
UA_encodeBinary(const void *p, const UA_DataType *type,
                UA_ByteString *outBuf, UA_EncodeBinaryOptions *options) {
    /* Allocate buffer */
    UA_Boolean allocated = false;
    status res = UA_STATUSCODE_GOOD;
    if(outBuf->length == 0) {
        size_t len = UA_calcSizeBinary(p, type, options);
        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, options, 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(Ctx *UA_RESTRICT ctx, void *UA_RESTRICT dst,
                           const UA_DataType *type) {
    (void)dst, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static status
decodeBinaryStructure(Ctx *UA_RESTRICT ctx, void *UA_RESTRICT dst,
                      const UA_DataType *type) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    status ret = UA_STATUSCODE_GOOD;
    u8 membersSize = type->membersSize;

    /* Loop over members */
    for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;

        /* Array */
        if(m->isArray) {
            size_t *length = (size_t*)ptr;
            ptr += sizeof(size_t);
            ret = Array_decodeBinary(ctx, (void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt);
            ptr += sizeof(void*);
            continue;
        }

        /* Scalar */
        ret = decodeBinaryJumpTable[mt->typeKind](ctx, (void *UA_RESTRICT)ptr, mt);
        ptr += mt->memSize;
    }

    ctx->depth--;
    return ret;
}

static status
decodeBinaryStructureWithOptFields(Ctx *UA_RESTRICT ctx, void *UA_RESTRICT dst,
                                   const UA_DataType *type) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    UA_UInt32 encodingMask = 0;
    status ret = UInt32_decodeBinary(ctx, &encodingMask, &UA_TYPES[UA_TYPES_UINT32]);
    UA_CHECK_STATUS(ret, ctx->depth--; return ret);

    /* Loop over members */
    for(size_t i = 0, o = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;
        if(m->isOptional) {
            if(!(encodingMask & (UA_UInt32) ( (UA_UInt32) 1<<(o++)))) {
                /* Optional field is not contained */
                if(m->isArray)
                    ptr += sizeof(size_t);
            } else if(m->isArray) {
                /* Optional Array */
                size_t *length = (size_t*)ptr;
                ptr += sizeof(size_t);
                ret = Array_decodeBinary(ctx, (void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt);
            } else {
                /* Optional Scalar */
                *(void *UA_RESTRICT *UA_RESTRICT) ptr = ctxCalloc(ctx, 1, mt->memSize);
                UA_CHECK_MEM(*(void *UA_RESTRICT *UA_RESTRICT) ptr, return UA_STATUSCODE_BADOUTOFMEMORY);
                ret = decodeBinaryJumpTable[mt->typeKind](ctx, *(void *UA_RESTRICT *UA_RESTRICT)ptr, mt);
            }
            ptr += sizeof(void *);
            continue;
        }

        /* Array */
        if(m->isArray) {
            size_t *length = (size_t *)ptr;
            ptr += sizeof(size_t);
            ret = Array_decodeBinary(ctx, (void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt);
            ptr += sizeof(void *);
            continue;
        }

        /* Scalar */
        ret = decodeBinaryJumpTable[mt->typeKind](ctx, (void *UA_RESTRICT)ptr, mt);
        ptr += mt->memSize;
    }
    ctx->depth--;
    return ret;
}

static status
decodeBinaryUnion(Ctx *UA_RESTRICT ctx, void *UA_RESTRICT dst,
                  const UA_DataType *type) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);

    /* Decode the selection directly into the switchfield */
    status ret = DECODE_DIRECT(dst, UInt32);
    UA_CHECK_STATUS(ret, return ret);

    /* No content? */
    UA_UInt32 selection = *(UA_UInt32*)dst;
    if(selection == 0)
        return UA_STATUSCODE_GOOD;

    /* Sanity check the selection */
    UA_CHECK(selection-1 < type->membersSize,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Select the member */
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;

    /* Decode */
    ctx->depth++;
    uintptr_t ptr = ((uintptr_t)dst) + m->padding; /* includes the switchfield */
    if(!m->isArray) {
        ret = decodeBinaryJumpTable[mt->typeKind](ctx, (void *UA_RESTRICT)ptr, mt);
    } else {
        size_t *length = (size_t *)ptr;
        ptr += sizeof(size_t);
        ret = Array_decodeBinary(ctx, (void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt);
    }
    ctx->depth--;
    return ret;
}

const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS] = {
    Boolean_decodeBinary,
    Byte_decodeBinary, /* SByte */
    Byte_decodeBinary,
    UInt16_decodeBinary, /* Int16 */
    UInt16_decodeBinary,
    UInt32_decodeBinary, /* Int32 */
    UInt32_decodeBinary,
    UInt64_decodeBinary, /* Int64 */
    UInt64_decodeBinary,
    Float_decodeBinary,
    Double_decodeBinary,
    String_decodeBinary,
    UInt64_decodeBinary, /* DateTime */
    Guid_decodeBinary,
    String_decodeBinary, /* ByteString */
    String_decodeBinary, /* XmlElement */
    NodeId_decodeBinary,
    ExpandedNodeId_decodeBinary,
    UInt32_decodeBinary, /* StatusCode */
    QualifiedName_decodeBinary,
    LocalizedText_decodeBinary,
    ExtensionObject_decodeBinary,
    DataValue_decodeBinary,
    Variant_decodeBinary,
    DiagnosticInfo_decodeBinary,
    decodeBinaryNotImplemented, /* Decimal */
    UInt32_decodeBinary, /* Enumeration */
    decodeBinaryStructure,
    decodeBinaryStructureWithOptFields, /* Structure with optional fields */
    decodeBinaryUnion, /* Union */
    decodeBinaryNotImplemented /* BitfieldCluster */
};

status
UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset,
                        void *dst, const UA_DataType *type,
                        UA_DecodeBinaryOptions *options) {
    /* Set up the context */
    Ctx ctx;
    ctx.pos = &src->data[*offset];
    ctx.end = &src->data[src->length];
    ctx.depth = 0;
    if(options)
        ctx.opts = *options;
    else
        memset(&ctx.opts, 0, sizeof(UA_DecodeBinaryOptions));

    /* Decode */
    memset(dst, 0, type->memSize); /* Initialize the value */
    status ret = decodeBinaryJumpTable[type->typeKind](&ctx, dst, type);

    if(UA_LIKELY(ret == UA_STATUSCODE_GOOD)) {
        /* Set the new offset */
        *offset = (size_t)(ctx.pos - src->data) / sizeof(u8);
        if(options)
            options->decodedLength = *offset;
    } else {
        /* Clean up */
        ctxClear(&ctx, dst, type);
    }

    return ret;
}

UA_StatusCode
UA_decodeBinary(const UA_ByteString *inBuf,
                void *p, const UA_DataType *type,
                UA_DecodeBinaryOptions *options) {
    size_t offset = 0;
    return UA_decodeBinaryInternal(inBuf, &offset, p, type, options);
}

/**
 * Compute the Message Size
 * ------------------------
 * The following methods are used to compute the length of a datum in binary
 * encoding. If the end-ptr is NULL, then the normal encoding functions do not
 * throw an error when the buffer limits are exceeded. */

size_t
UA_calcSizeBinary(const void *p, const UA_DataType *type,
                  UA_EncodeBinaryOptions *options) {
    u8 *pos = NULL;
    const u8 *posEnd = NULL;
    UA_StatusCode res = UA_encodeBinaryInternal(p, type, &pos, &posEnd, options, NULL, NULL);
    if(res != UA_STATUSCODE_GOOD)
        return 0;
    return (size_t)(uintptr_t)pos;
}

/**** amalgamated original file "1_build/src_generated/open62541/types_generated.c" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/


/* Boolean */
#define Boolean_members NULL

/* SByte */
#define SByte_members NULL

/* Byte */
#define Byte_members NULL

/* Int16 */
#define Int16_members NULL

/* UInt16 */
#define UInt16_members NULL

/* Int32 */
#define Int32_members NULL

/* UInt32 */
#define UInt32_members NULL

/* Int64 */
#define Int64_members NULL

/* UInt64 */
#define UInt64_members NULL

/* Float */
#define Float_members NULL

/* Double */
#define Double_members NULL

/* String */
#define String_members NULL

/* DateTime */
#define DateTime_members NULL

/* Guid */
#define Guid_members NULL

/* ByteString */
#define ByteString_members NULL

/* XmlElement */
#define XmlElement_members NULL

/* NodeId */
#define NodeId_members NULL

/* ExpandedNodeId */
#define ExpandedNodeId_members NULL

/* StatusCode */
#define StatusCode_members NULL

/* QualifiedName */
#define QualifiedName_members NULL

/* LocalizedText */
#define LocalizedText_members NULL

/* ExtensionObject */
#define ExtensionObject_members NULL

/* DataValue */
#define DataValue_members NULL

/* Variant */
#define Variant_members NULL

/* DiagnosticInfo */
#define DiagnosticInfo_members NULL

/* NamingRuleType */
static UA_DataTypeMember NamingRuleType_members[3] = {
{
    UA_TYPENAME("Mandatory") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Optional") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Constraint") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* Enumeration */
#define Enumeration_members NULL

/* ImageBMP */
#define ImageBMP_members NULL

/* ImageGIF */
#define ImageGIF_members NULL

/* ImageJPG */
#define ImageJPG_members NULL

/* ImagePNG */
#define ImagePNG_members NULL

/* AudioDataType */
#define AudioDataType_members NULL

/* UriString */
#define UriString_members NULL

/* BitFieldMaskDataType */
#define BitFieldMaskDataType_members NULL

/* SemanticVersionString */
#define SemanticVersionString_members NULL

/* KeyValuePair */
static UA_DataTypeMember KeyValuePair_members[2] = {
{
    UA_TYPENAME("Key") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_KeyValuePair, value) - offsetof(UA_KeyValuePair, key) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AdditionalParametersType */
static UA_DataTypeMember AdditionalParametersType_members[1] = {
{
    UA_TYPENAME("Parameters") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* EphemeralKeyType */
static UA_DataTypeMember EphemeralKeyType_members[2] = {
{
    UA_TYPENAME("PublicKey") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Signature") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_EphemeralKeyType, signature) - offsetof(UA_EphemeralKeyType, publicKey) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* RationalNumber */
static UA_DataTypeMember RationalNumber_members[2] = {
{
    UA_TYPENAME("Numerator") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Denominator") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RationalNumber, denominator) - offsetof(UA_RationalNumber, numerator) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ThreeDVector */
static UA_DataTypeMember ThreeDVector_members[3] = {
{
    UA_TYPENAME("X") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Y") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ThreeDVector, y) - offsetof(UA_ThreeDVector, x) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Z") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ThreeDVector, z) - offsetof(UA_ThreeDVector, y) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ThreeDCartesianCoordinates */
static UA_DataTypeMember ThreeDCartesianCoordinates_members[3] = {
{
    UA_TYPENAME("X") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Y") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ThreeDCartesianCoordinates, y) - offsetof(UA_ThreeDCartesianCoordinates, x) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Z") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ThreeDCartesianCoordinates, z) - offsetof(UA_ThreeDCartesianCoordinates, y) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ThreeDOrientation */
static UA_DataTypeMember ThreeDOrientation_members[3] = {
{
    UA_TYPENAME("A") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("B") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ThreeDOrientation, b) - offsetof(UA_ThreeDOrientation, a) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("C") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ThreeDOrientation, c) - offsetof(UA_ThreeDOrientation, b) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ThreeDFrame */
static UA_DataTypeMember ThreeDFrame_members[2] = {
{
    UA_TYPENAME("CartesianCoordinates") /* .memberName */
    &UA_TYPES[UA_TYPES_THREEDCARTESIANCOORDINATES], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Orientation") /* .memberName */
    &UA_TYPES[UA_TYPES_THREEDORIENTATION], /* .memberType */
    offsetof(UA_ThreeDFrame, orientation) - offsetof(UA_ThreeDFrame, cartesianCoordinates) - sizeof(UA_ThreeDCartesianCoordinates), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* OpenFileMode */
static UA_DataTypeMember OpenFileMode_members[4] = {
{
    UA_TYPENAME("Read") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Write") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("EraseExisting") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Append") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* IdentityCriteriaType */
static UA_DataTypeMember IdentityCriteriaType_members[8] = {
{
    UA_TYPENAME("UserName") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Thumbprint") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Role") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("GroupId") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Anonymous") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("AuthenticatedUser") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Application") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("X509Subject") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* IdentityMappingRuleType */
static UA_DataTypeMember IdentityMappingRuleType_members[2] = {
{
    UA_TYPENAME("CriteriaType") /* .memberName */
    &UA_TYPES[UA_TYPES_IDENTITYCRITERIATYPE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Criteria") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_IdentityMappingRuleType, criteria) - offsetof(UA_IdentityMappingRuleType, criteriaType) - sizeof(UA_IdentityCriteriaType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CurrencyUnitType */
static UA_DataTypeMember CurrencyUnitType_members[4] = {
{
    UA_TYPENAME("NumericCode") /* .memberName */
    &UA_TYPES[UA_TYPES_INT16], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Exponent") /* .memberName */
    &UA_TYPES[UA_TYPES_SBYTE], /* .memberType */
    offsetof(UA_CurrencyUnitType, exponent) - offsetof(UA_CurrencyUnitType, numericCode) - sizeof(UA_Int16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AlphabeticCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_CurrencyUnitType, alphabeticCode) - offsetof(UA_CurrencyUnitType, exponent) - sizeof(UA_SByte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Currency") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_CurrencyUnitType, currency) - offsetof(UA_CurrencyUnitType, alphabeticCode) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TrustListMasks */
static UA_DataTypeMember TrustListMasks_members[6] = {
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("TrustedCertificates") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("TrustedCrls") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("IssuerCertificates") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("IssuerCrls") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("All") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* TrustListDataType */
static UA_DataTypeMember TrustListDataType_members[5] = {
{
    UA_TYPENAME("SpecifiedLists") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TrustedCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, trustedCertificatesSize) - offsetof(UA_TrustListDataType, specifiedLists) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TrustedCrls") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, trustedCrlsSize) - offsetof(UA_TrustListDataType, trustedCertificates) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuerCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, issuerCertificatesSize) - offsetof(UA_TrustListDataType, trustedCrls) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuerCrls") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, issuerCrlsSize) - offsetof(UA_TrustListDataType, issuerCertificates) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DecimalDataType */
static UA_DataTypeMember DecimalDataType_members[2] = {
{
    UA_TYPENAME("Scale") /* .memberName */
    &UA_TYPES[UA_TYPES_INT16], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_DecimalDataType, value) - offsetof(UA_DecimalDataType, scale) - sizeof(UA_Int16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DataTypeDescription */
static UA_DataTypeMember DataTypeDescription_members[2] = {
{
    UA_TYPENAME("DataTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_DataTypeDescription, name) - offsetof(UA_DataTypeDescription, dataTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SimpleTypeDescription */
static UA_DataTypeMember SimpleTypeDescription_members[4] = {
{
    UA_TYPENAME("DataTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_SimpleTypeDescription, name) - offsetof(UA_SimpleTypeDescription, dataTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BaseDataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_SimpleTypeDescription, baseDataType) - offsetof(UA_SimpleTypeDescription, name) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuiltInType") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_SimpleTypeDescription, builtInType) - offsetof(UA_SimpleTypeDescription, baseDataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PortableQualifiedName */
static UA_DataTypeMember PortableQualifiedName_members[2] = {
{
    UA_TYPENAME("NamespaceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PortableQualifiedName, name) - offsetof(UA_PortableQualifiedName, namespaceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PortableNodeId */
static UA_DataTypeMember PortableNodeId_members[2] = {
{
    UA_TYPENAME("NamespaceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Identifier") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_PortableNodeId, identifier) - offsetof(UA_PortableNodeId, namespaceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* UnsignedRationalNumber */
static UA_DataTypeMember UnsignedRationalNumber_members[2] = {
{
    UA_TYPENAME("Numerator") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Denominator") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_UnsignedRationalNumber, denominator) - offsetof(UA_UnsignedRationalNumber, numerator) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubState */
static UA_DataTypeMember PubSubState_members[5] = {
{
    UA_TYPENAME("Disabled") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Paused") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Operational") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Error") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("PreOperational") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* DataSetFieldFlags */
#define DataSetFieldFlags_members NULL

/* ConfigurationVersionDataType */
static UA_DataTypeMember ConfigurationVersionDataType_members[2] = {
{
    UA_TYPENAME("MajorVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MinorVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ConfigurationVersionDataType, minorVersion) - offsetof(UA_ConfigurationVersionDataType, majorVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PublishedVariableDataType */
static UA_DataTypeMember PublishedVariableDataType_members[8] = {
{
    UA_TYPENAME("PublishedVariable") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PublishedVariableDataType, attributeId) - offsetof(UA_PublishedVariableDataType, publishedVariable) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SamplingIntervalHint") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_PublishedVariableDataType, samplingIntervalHint) - offsetof(UA_PublishedVariableDataType, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeadbandType") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PublishedVariableDataType, deadbandType) - offsetof(UA_PublishedVariableDataType, samplingIntervalHint) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeadbandValue") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_PublishedVariableDataType, deadbandValue) - offsetof(UA_PublishedVariableDataType, deadbandType) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PublishedVariableDataType, indexRange) - offsetof(UA_PublishedVariableDataType, deadbandValue) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubstituteValue") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_PublishedVariableDataType, substituteValue) - offsetof(UA_PublishedVariableDataType, indexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MetaDataProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_PublishedVariableDataType, metaDataPropertiesSize) - offsetof(UA_PublishedVariableDataType, substituteValue) - sizeof(UA_Variant), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PublishedDataItemsDataType */
static UA_DataTypeMember PublishedDataItemsDataType_members[1] = {
{
    UA_TYPENAME("PublishedData") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PublishedDataSetCustomSourceDataType */
static UA_DataTypeMember PublishedDataSetCustomSourceDataType_members[1] = {
{
    UA_TYPENAME("CyclicDataSet") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DataSetFieldContentMask */
#define DataSetFieldContentMask_members NULL

/* DataSetWriterDataType */
static UA_DataTypeMember DataSetWriterDataType_members[9] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DataSetWriterDataType, enabled) - offsetof(UA_DataSetWriterDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetWriterId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_DataSetWriterDataType, dataSetWriterId) - offsetof(UA_DataSetWriterDataType, enabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetFieldContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETFIELDCONTENTMASK], /* .memberType */
    offsetof(UA_DataSetWriterDataType, dataSetFieldContentMask) - offsetof(UA_DataSetWriterDataType, dataSetWriterId) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("KeyFrameCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataSetWriterDataType, keyFrameCount) - offsetof(UA_DataSetWriterDataType, dataSetFieldContentMask) - sizeof(UA_DataSetFieldContentMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DataSetWriterDataType, dataSetName) - offsetof(UA_DataSetWriterDataType, keyFrameCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetWriterProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_DataSetWriterDataType, dataSetWriterPropertiesSize) - offsetof(UA_DataSetWriterDataType, dataSetName) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DataSetWriterDataType, transportSettings) - offsetof(UA_DataSetWriterDataType, dataSetWriterProperties) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DataSetWriterDataType, messageSettings) - offsetof(UA_DataSetWriterDataType, transportSettings) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* NetworkAddressDataType */
static UA_DataTypeMember NetworkAddressDataType_members[1] = {
{
    UA_TYPENAME("NetworkInterface") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* NetworkAddressUrlDataType */
static UA_DataTypeMember NetworkAddressUrlDataType_members[2] = {
{
    UA_TYPENAME("NetworkInterface") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Url") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_NetworkAddressUrlDataType, url) - offsetof(UA_NetworkAddressUrlDataType, networkInterface) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* OverrideValueHandling */
static UA_DataTypeMember OverrideValueHandling_members[3] = {
{
    UA_TYPENAME("Disabled") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("LastUsableValue") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("OverrideValue") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* StandaloneSubscribedDataSetRefDataType */
static UA_DataTypeMember StandaloneSubscribedDataSetRefDataType_members[1] = {
{
    UA_TYPENAME("DataSetName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DataSetOrderingType */
static UA_DataTypeMember DataSetOrderingType_members[3] = {
{
    UA_TYPENAME("Undefined") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("AscendingWriterId") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("AscendingWriterIdSingle") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* UadpNetworkMessageContentMask */
#define UadpNetworkMessageContentMask_members NULL

/* UadpWriterGroupMessageDataType */
static UA_DataTypeMember UadpWriterGroupMessageDataType_members[5] = {
{
    UA_TYPENAME("GroupVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetOrdering") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETORDERINGTYPE], /* .memberType */
    offsetof(UA_UadpWriterGroupMessageDataType, dataSetOrdering) - offsetof(UA_UadpWriterGroupMessageDataType, groupVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NetworkMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UADPNETWORKMESSAGECONTENTMASK], /* .memberType */
    offsetof(UA_UadpWriterGroupMessageDataType, networkMessageContentMask) - offsetof(UA_UadpWriterGroupMessageDataType, dataSetOrdering) - sizeof(UA_DataSetOrderingType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SamplingOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_UadpWriterGroupMessageDataType, samplingOffset) - offsetof(UA_UadpWriterGroupMessageDataType, networkMessageContentMask) - sizeof(UA_UadpNetworkMessageContentMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_UadpWriterGroupMessageDataType, publishingOffsetSize) - offsetof(UA_UadpWriterGroupMessageDataType, samplingOffset) - sizeof(UA_Double), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* UadpDataSetMessageContentMask */
#define UadpDataSetMessageContentMask_members NULL

/* UadpDataSetWriterMessageDataType */
static UA_DataTypeMember UadpDataSetWriterMessageDataType_members[4] = {
{
    UA_TYPENAME("DataSetMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UADPDATASETMESSAGECONTENTMASK], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConfiguredSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_UadpDataSetWriterMessageDataType, configuredSize) - offsetof(UA_UadpDataSetWriterMessageDataType, dataSetMessageContentMask) - sizeof(UA_UadpDataSetMessageContentMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NetworkMessageNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_UadpDataSetWriterMessageDataType, networkMessageNumber) - offsetof(UA_UadpDataSetWriterMessageDataType, configuredSize) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_UadpDataSetWriterMessageDataType, dataSetOffset) - offsetof(UA_UadpDataSetWriterMessageDataType, networkMessageNumber) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* UadpDataSetReaderMessageDataType */
static UA_DataTypeMember UadpDataSetReaderMessageDataType_members[9] = {
{
    UA_TYPENAME("GroupVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NetworkMessageNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, networkMessageNumber) - offsetof(UA_UadpDataSetReaderMessageDataType, groupVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, dataSetOffset) - offsetof(UA_UadpDataSetReaderMessageDataType, networkMessageNumber) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetClassId") /* .memberName */
    &UA_TYPES[UA_TYPES_GUID], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, dataSetClassId) - offsetof(UA_UadpDataSetReaderMessageDataType, dataSetOffset) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NetworkMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UADPNETWORKMESSAGECONTENTMASK], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, networkMessageContentMask) - offsetof(UA_UadpDataSetReaderMessageDataType, dataSetClassId) - sizeof(UA_Guid), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UADPDATASETMESSAGECONTENTMASK], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, dataSetMessageContentMask) - offsetof(UA_UadpDataSetReaderMessageDataType, networkMessageContentMask) - sizeof(UA_UadpNetworkMessageContentMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, publishingInterval) - offsetof(UA_UadpDataSetReaderMessageDataType, dataSetMessageContentMask) - sizeof(UA_UadpDataSetMessageContentMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiveOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, receiveOffset) - offsetof(UA_UadpDataSetReaderMessageDataType, publishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProcessingOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_UadpDataSetReaderMessageDataType, processingOffset) - offsetof(UA_UadpDataSetReaderMessageDataType, receiveOffset) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* JsonNetworkMessageContentMask */
#define JsonNetworkMessageContentMask_members NULL

/* JsonWriterGroupMessageDataType */
static UA_DataTypeMember JsonWriterGroupMessageDataType_members[1] = {
{
    UA_TYPENAME("NetworkMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_JSONNETWORKMESSAGECONTENTMASK], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* JsonDataSetMessageContentMask */
#define JsonDataSetMessageContentMask_members NULL

/* JsonDataSetWriterMessageDataType */
static UA_DataTypeMember JsonDataSetWriterMessageDataType_members[1] = {
{
    UA_TYPENAME("DataSetMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_JSONDATASETMESSAGECONTENTMASK], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* JsonDataSetReaderMessageDataType */
static UA_DataTypeMember JsonDataSetReaderMessageDataType_members[2] = {
{
    UA_TYPENAME("NetworkMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_JSONNETWORKMESSAGECONTENTMASK], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetMessageContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_JSONDATASETMESSAGECONTENTMASK], /* .memberType */
    offsetof(UA_JsonDataSetReaderMessageDataType, dataSetMessageContentMask) - offsetof(UA_JsonDataSetReaderMessageDataType, networkMessageContentMask) - sizeof(UA_JsonNetworkMessageContentMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TransmitQosPriorityDataType */
static UA_DataTypeMember TransmitQosPriorityDataType_members[1] = {
{
    UA_TYPENAME("PriorityLabel") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ReceiveQosPriorityDataType */
static UA_DataTypeMember ReceiveQosPriorityDataType_members[1] = {
{
    UA_TYPENAME("PriorityLabel") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DatagramConnectionTransportDataType */
static UA_DataTypeMember DatagramConnectionTransportDataType_members[1] = {
{
    UA_TYPENAME("DiscoveryAddress") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DatagramConnectionTransport2DataType */
static UA_DataTypeMember DatagramConnectionTransport2DataType_members[5] = {
{
    UA_TYPENAME("DiscoveryAddress") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryAnnounceRate") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DatagramConnectionTransport2DataType, discoveryAnnounceRate) - offsetof(UA_DatagramConnectionTransport2DataType, discoveryAddress) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryMaxMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DatagramConnectionTransport2DataType, discoveryMaxMessageSize) - offsetof(UA_DatagramConnectionTransport2DataType, discoveryAnnounceRate) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QosCategory") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DatagramConnectionTransport2DataType, qosCategory) - offsetof(UA_DatagramConnectionTransport2DataType, discoveryMaxMessageSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DatagramQos") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DatagramConnectionTransport2DataType, datagramQosSize) - offsetof(UA_DatagramConnectionTransport2DataType, qosCategory) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DatagramWriterGroupTransportDataType */
static UA_DataTypeMember DatagramWriterGroupTransportDataType_members[2] = {
{
    UA_TYPENAME("MessageRepeatCount") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageRepeatDelay") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_DatagramWriterGroupTransportDataType, messageRepeatDelay) - offsetof(UA_DatagramWriterGroupTransportDataType, messageRepeatCount) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DatagramWriterGroupTransport2DataType */
static UA_DataTypeMember DatagramWriterGroupTransport2DataType_members[7] = {
{
    UA_TYPENAME("MessageRepeatCount") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageRepeatDelay") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_DatagramWriterGroupTransport2DataType, messageRepeatDelay) - offsetof(UA_DatagramWriterGroupTransport2DataType, messageRepeatCount) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Address") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DatagramWriterGroupTransport2DataType, address) - offsetof(UA_DatagramWriterGroupTransport2DataType, messageRepeatDelay) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QosCategory") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DatagramWriterGroupTransport2DataType, qosCategory) - offsetof(UA_DatagramWriterGroupTransport2DataType, address) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DatagramQos") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DatagramWriterGroupTransport2DataType, datagramQosSize) - offsetof(UA_DatagramWriterGroupTransport2DataType, qosCategory) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryAnnounceRate") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DatagramWriterGroupTransport2DataType, discoveryAnnounceRate) - offsetof(UA_DatagramWriterGroupTransport2DataType, datagramQos) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Topic") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DatagramWriterGroupTransport2DataType, topic) - offsetof(UA_DatagramWriterGroupTransport2DataType, discoveryAnnounceRate) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DatagramDataSetReaderTransportDataType */
static UA_DataTypeMember DatagramDataSetReaderTransportDataType_members[4] = {
{
    UA_TYPENAME("Address") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QosCategory") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DatagramDataSetReaderTransportDataType, qosCategory) - offsetof(UA_DatagramDataSetReaderTransportDataType, address) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DatagramQos") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DatagramDataSetReaderTransportDataType, datagramQosSize) - offsetof(UA_DatagramDataSetReaderTransportDataType, qosCategory) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Topic") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DatagramDataSetReaderTransportDataType, topic) - offsetof(UA_DatagramDataSetReaderTransportDataType, datagramQos) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrokerConnectionTransportDataType */
static UA_DataTypeMember BrokerConnectionTransportDataType_members[2] = {
{
    UA_TYPENAME("ResourceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerConnectionTransportDataType, authenticationProfileUri) - offsetof(UA_BrokerConnectionTransportDataType, resourceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrokerTransportQualityOfService */
static UA_DataTypeMember BrokerTransportQualityOfService_members[5] = {
{
    UA_TYPENAME("NotSpecified") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("BestEffort") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("AtLeastOnce") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("AtMostOnce") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ExactlyOnce") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* BrokerWriterGroupTransportDataType */
static UA_DataTypeMember BrokerWriterGroupTransportDataType_members[4] = {
{
    UA_TYPENAME("QueueName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ResourceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerWriterGroupTransportDataType, resourceUri) - offsetof(UA_BrokerWriterGroupTransportDataType, queueName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerWriterGroupTransportDataType, authenticationProfileUri) - offsetof(UA_BrokerWriterGroupTransportDataType, resourceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedDeliveryGuarantee") /* .memberName */
    &UA_TYPES[UA_TYPES_BROKERTRANSPORTQUALITYOFSERVICE], /* .memberType */
    offsetof(UA_BrokerWriterGroupTransportDataType, requestedDeliveryGuarantee) - offsetof(UA_BrokerWriterGroupTransportDataType, authenticationProfileUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrokerDataSetWriterTransportDataType */
static UA_DataTypeMember BrokerDataSetWriterTransportDataType_members[6] = {
{
    UA_TYPENAME("QueueName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ResourceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerDataSetWriterTransportDataType, resourceUri) - offsetof(UA_BrokerDataSetWriterTransportDataType, queueName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerDataSetWriterTransportDataType, authenticationProfileUri) - offsetof(UA_BrokerDataSetWriterTransportDataType, resourceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedDeliveryGuarantee") /* .memberName */
    &UA_TYPES[UA_TYPES_BROKERTRANSPORTQUALITYOFSERVICE], /* .memberType */
    offsetof(UA_BrokerDataSetWriterTransportDataType, requestedDeliveryGuarantee) - offsetof(UA_BrokerDataSetWriterTransportDataType, authenticationProfileUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MetaDataQueueName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerDataSetWriterTransportDataType, metaDataQueueName) - offsetof(UA_BrokerDataSetWriterTransportDataType, requestedDeliveryGuarantee) - sizeof(UA_BrokerTransportQualityOfService), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MetaDataUpdateTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_BrokerDataSetWriterTransportDataType, metaDataUpdateTime) - offsetof(UA_BrokerDataSetWriterTransportDataType, metaDataQueueName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrokerDataSetReaderTransportDataType */
static UA_DataTypeMember BrokerDataSetReaderTransportDataType_members[5] = {
{
    UA_TYPENAME("QueueName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ResourceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerDataSetReaderTransportDataType, resourceUri) - offsetof(UA_BrokerDataSetReaderTransportDataType, queueName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerDataSetReaderTransportDataType, authenticationProfileUri) - offsetof(UA_BrokerDataSetReaderTransportDataType, resourceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedDeliveryGuarantee") /* .memberName */
    &UA_TYPES[UA_TYPES_BROKERTRANSPORTQUALITYOFSERVICE], /* .memberType */
    offsetof(UA_BrokerDataSetReaderTransportDataType, requestedDeliveryGuarantee) - offsetof(UA_BrokerDataSetReaderTransportDataType, authenticationProfileUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MetaDataQueueName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BrokerDataSetReaderTransportDataType, metaDataQueueName) - offsetof(UA_BrokerDataSetReaderTransportDataType, requestedDeliveryGuarantee) - sizeof(UA_BrokerTransportQualityOfService), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubConfigurationRefMask */
#define PubSubConfigurationRefMask_members NULL

/* PubSubConfigurationRefDataType */
static UA_DataTypeMember PubSubConfigurationRefDataType_members[4] = {
{
    UA_TYPENAME("ConfigurationMask") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONREFMASK], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ElementIndex") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_PubSubConfigurationRefDataType, elementIndex) - offsetof(UA_PubSubConfigurationRefDataType, configurationMask) - sizeof(UA_PubSubConfigurationRefMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConnectionIndex") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_PubSubConfigurationRefDataType, connectionIndex) - offsetof(UA_PubSubConfigurationRefDataType, elementIndex) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GroupIndex") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_PubSubConfigurationRefDataType, groupIndex) - offsetof(UA_PubSubConfigurationRefDataType, connectionIndex) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubConfigurationValueDataType */
static UA_DataTypeMember PubSubConfigurationValueDataType_members[3] = {
{
    UA_TYPENAME("ConfigurationElement") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONREFDATATYPE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PubSubConfigurationValueDataType, name) - offsetof(UA_PubSubConfigurationValueDataType, configurationElement) - sizeof(UA_PubSubConfigurationRefDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Identifier") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_PubSubConfigurationValueDataType, identifier) - offsetof(UA_PubSubConfigurationValueDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DiagnosticsLevel */
static UA_DataTypeMember DiagnosticsLevel_members[5] = {
{
    UA_TYPENAME("Basic") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Advanced") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Info") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Log") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Debug") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* PubSubDiagnosticsCounterClassification */
static UA_DataTypeMember PubSubDiagnosticsCounterClassification_members[2] = {
{
    UA_TYPENAME("Information") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Error") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* AliasNameDataType */
static UA_DataTypeMember AliasNameDataType_members[2] = {
{
    UA_TYPENAME("AliasName") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferencedNodes") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_AliasNameDataType, referencedNodesSize) - offsetof(UA_AliasNameDataType, aliasName) - sizeof(UA_QualifiedName), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PasswordOptionsMask */
#define PasswordOptionsMask_members NULL

/* UserConfigurationMask */
#define UserConfigurationMask_members NULL

/* UserManagementDataType */
static UA_DataTypeMember UserManagementDataType_members[3] = {
{
    UA_TYPENAME("UserName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_USERCONFIGURATIONMASK], /* .memberType */
    offsetof(UA_UserManagementDataType, userConfiguration) - offsetof(UA_UserManagementDataType, userName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserManagementDataType, description) - offsetof(UA_UserManagementDataType, userConfiguration) - sizeof(UA_UserConfigurationMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* Duplex */
static UA_DataTypeMember Duplex_members[3] = {
{
    UA_TYPENAME("Full") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Half") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Unknown") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* InterfaceAdminStatus */
static UA_DataTypeMember InterfaceAdminStatus_members[3] = {
{
    UA_TYPENAME("Up") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Down") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Testing") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* InterfaceOperStatus */
static UA_DataTypeMember InterfaceOperStatus_members[7] = {
{
    UA_TYPENAME("Up") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Down") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Testing") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Unknown") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Dormant") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("NotPresent") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("LowerLayerDown") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* NegotiationStatus */
static UA_DataTypeMember NegotiationStatus_members[5] = {
{
    UA_TYPENAME("InProgress") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Complete") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Failed") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Unknown") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("NoNegotiation") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* TsnFailureCode */
static UA_DataTypeMember TsnFailureCode_members[26] = {
{
    UA_TYPENAME("NoFailure") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("InsufficientBandwidth") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("InsufficientResources") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("InsufficientTrafficClassBandwidth") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StreamIdInUse") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StreamDestinationAddressInUse") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StreamPreemptedByHigherRank") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("LatencyHasChanged") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("EgressPortNotAvbCapable") /* .memberName */
    (const UA_DataType *)8, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("UseDifferentDestinationAddress") /* .memberName */
    (const UA_DataType *)9, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("OutOfMsrpResources") /* .memberName */
    (const UA_DataType *)10, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("OutOfMmrpResources") /* .memberName */
    (const UA_DataType *)11, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("CannotStoreDestinationAddress") /* .memberName */
    (const UA_DataType *)12, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("PriorityIsNotAnSrcClass") /* .memberName */
    (const UA_DataType *)13, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("MaxFrameSizeTooLarge") /* .memberName */
    (const UA_DataType *)14, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("MaxFanInPortsLimitReached") /* .memberName */
    (const UA_DataType *)15, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("FirstValueChangedForStreamId") /* .memberName */
    (const UA_DataType *)16, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("VlanBlockedOnEgress") /* .memberName */
    (const UA_DataType *)17, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("VlanTaggingDisabledOnEgress") /* .memberName */
    (const UA_DataType *)18, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("SrClassPriorityMismatch") /* .memberName */
    (const UA_DataType *)19, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("FeatureNotPropagated") /* .memberName */
    (const UA_DataType *)20, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("MaxLatencyExceeded") /* .memberName */
    (const UA_DataType *)21, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("BridgeDoesNotProvideNetworkId") /* .memberName */
    (const UA_DataType *)22, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StreamTransformNotSupported") /* .memberName */
    (const UA_DataType *)23, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StreamIdTypeNotSupported") /* .memberName */
    (const UA_DataType *)24, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("FeatureNotSupported") /* .memberName */
    (const UA_DataType *)25, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* TsnStreamState */
static UA_DataTypeMember TsnStreamState_members[5] = {
{
    UA_TYPENAME("Disabled") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Configuring") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Ready") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Operational") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Error") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* TsnTalkerStatus */
static UA_DataTypeMember TsnTalkerStatus_members[3] = {
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Ready") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Failed") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* TsnListenerStatus */
static UA_DataTypeMember TsnListenerStatus_members[4] = {
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Ready") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("PartialFailed") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Failed") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* PriorityMappingEntryType */
static UA_DataTypeMember PriorityMappingEntryType_members[4] = {
{
    UA_TYPENAME("MappingUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PriorityLabel") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PriorityMappingEntryType, priorityLabel) - offsetof(UA_PriorityMappingEntryType, mappingUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PriorityValue_PCP") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_PriorityMappingEntryType, priorityValue_PCP) - offsetof(UA_PriorityMappingEntryType, priorityLabel) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PriorityValue_DSCP") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PriorityMappingEntryType, priorityValue_DSCP) - offsetof(UA_PriorityMappingEntryType, priorityValue_PCP) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* IdType */
static UA_DataTypeMember IdType_members[4] = {
{
    UA_TYPENAME("Numeric") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("String") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Guid") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Opaque") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* NodeClass */
static UA_DataTypeMember NodeClass_members[9] = {
{
    UA_TYPENAME("Unspecified") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Object") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Variable") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Method") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ObjectType") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("VariableType") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ReferenceType") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("View") /* .memberName */
    (const UA_DataType *)8, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* PermissionType */
#define PermissionType_members NULL

/* AccessLevelType */
#define AccessLevelType_members NULL

/* AccessLevelExType */
#define AccessLevelExType_members NULL

/* EventNotifierType */
#define EventNotifierType_members NULL

/* AccessRestrictionType */
#define AccessRestrictionType_members NULL

/* RolePermissionType */
static UA_DataTypeMember RolePermissionType_members[2] = {
{
    UA_TYPENAME("RoleId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Permissions") /* .memberName */
    &UA_TYPES[UA_TYPES_PERMISSIONTYPE], /* .memberType */
    offsetof(UA_RolePermissionType, permissions) - offsetof(UA_RolePermissionType, roleId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* StructureType */
static UA_DataTypeMember StructureType_members[5] = {
{
    UA_TYPENAME("Structure") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StructureWithOptionalFields") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Union") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StructureWithSubtypedValues") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("UnionWithSubtypedValues") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* StructureField */
static UA_DataTypeMember StructureField_members[7] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_StructureField, description) - offsetof(UA_StructureField, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_StructureField, dataType) - offsetof(UA_StructureField, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_StructureField, valueRank) - offsetof(UA_StructureField, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_StructureField, arrayDimensionsSize) - offsetof(UA_StructureField, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxStringLength") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_StructureField, maxStringLength) - offsetof(UA_StructureField, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsOptional") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_StructureField, isOptional) - offsetof(UA_StructureField, maxStringLength) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* StructureDefinition */
static UA_DataTypeMember StructureDefinition_members[4] = {
{
    UA_TYPENAME("DefaultEncodingId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BaseDataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_StructureDefinition, baseDataType) - offsetof(UA_StructureDefinition, defaultEncodingId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StructureType") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTURETYPE], /* .memberType */
    offsetof(UA_StructureDefinition, structureType) - offsetof(UA_StructureDefinition, baseDataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Fields") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTUREFIELD], /* .memberType */
    offsetof(UA_StructureDefinition, fieldsSize) - offsetof(UA_StructureDefinition, structureType) - sizeof(UA_StructureType), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ReferenceNode */
static UA_DataTypeMember ReferenceNode_members[3] = {
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsInverse") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReferenceNode, isInverse) - offsetof(UA_ReferenceNode, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_ReferenceNode, targetId) - offsetof(UA_ReferenceNode, isInverse) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* Argument */
static UA_DataTypeMember Argument_members[5] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_Argument, dataType) - offsetof(UA_Argument, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_Argument, valueRank) - offsetof(UA_Argument, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_Argument, arrayDimensionsSize) - offsetof(UA_Argument, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_Argument, description) - offsetof(UA_Argument, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EnumValueType */
static UA_DataTypeMember EnumValueType_members[3] = {
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_INT64], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumValueType, displayName) - offsetof(UA_EnumValueType, value) - sizeof(UA_Int64), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumValueType, description) - offsetof(UA_EnumValueType, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EnumField */
static UA_DataTypeMember EnumField_members[4] = {
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_INT64], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumField, displayName) - offsetof(UA_EnumField, value) - sizeof(UA_Int64), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumField, description) - offsetof(UA_EnumField, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EnumField, name) - offsetof(UA_EnumField, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* OptionSet */
static UA_DataTypeMember OptionSet_members[2] = {
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValidBits") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_OptionSet, validBits) - offsetof(UA_OptionSet, value) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* NormalizedString */
#define NormalizedString_members NULL

/* DecimalString */
#define DecimalString_members NULL

/* DurationString */
#define DurationString_members NULL

/* TimeString */
#define TimeString_members NULL

/* DateString */
#define DateString_members NULL

/* Duration */
#define Duration_members NULL

/* UtcTime */
#define UtcTime_members NULL

/* LocaleId */
#define LocaleId_members NULL

/* TimeZoneDataType */
static UA_DataTypeMember TimeZoneDataType_members[2] = {
{
    UA_TYPENAME("Offset") /* .memberName */
    &UA_TYPES[UA_TYPES_INT16], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DaylightSavingInOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_TimeZoneDataType, daylightSavingInOffset) - offsetof(UA_TimeZoneDataType, offset) - sizeof(UA_Int16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* Index */
#define Index_members NULL

/* IntegerId */
#define IntegerId_members NULL

/* ApplicationType */
static UA_DataTypeMember ApplicationType_members[4] = {
{
    UA_TYPENAME("Server") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Client") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ClientAndServer") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryServer") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ApplicationDescription */
static UA_DataTypeMember ApplicationDescription_members[7] = {
{
    UA_TYPENAME("ApplicationUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProductUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, productUri) - offsetof(UA_ApplicationDescription, applicationUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ApplicationName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ApplicationDescription, applicationName) - offsetof(UA_ApplicationDescription, productUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ApplicationType") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONTYPE], /* .memberType */
    offsetof(UA_ApplicationDescription, applicationType) - offsetof(UA_ApplicationDescription, applicationName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GatewayServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, gatewayServerUri) - offsetof(UA_ApplicationDescription, applicationType) - sizeof(UA_ApplicationType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, discoveryProfileUri) - offsetof(UA_ApplicationDescription, gatewayServerUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryUrls") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, discoveryUrlsSize) - offsetof(UA_ApplicationDescription, discoveryProfileUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RequestHeader */
static UA_DataTypeMember RequestHeader_members[7] = {
{
    UA_TYPENAME("AuthenticationToken") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Timestamp") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_RequestHeader, timestamp) - offsetof(UA_RequestHeader, authenticationToken) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RequestHeader, requestHandle) - offsetof(UA_RequestHeader, timestamp) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReturnDiagnostics") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RequestHeader, returnDiagnostics) - offsetof(UA_RequestHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuditEntryId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RequestHeader, auditEntryId) - offsetof(UA_RequestHeader, returnDiagnostics) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimeoutHint") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RequestHeader, timeoutHint) - offsetof(UA_RequestHeader, auditEntryId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AdditionalHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_RequestHeader, additionalHeader) - offsetof(UA_RequestHeader, timeoutHint) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ResponseHeader */
static UA_DataTypeMember ResponseHeader_members[6] = {
{
    UA_TYPENAME("Timestamp") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ResponseHeader, requestHandle) - offsetof(UA_ResponseHeader, timestamp) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServiceResult") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ResponseHeader, serviceResult) - offsetof(UA_ResponseHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServiceDiagnostics") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ResponseHeader, serviceDiagnostics) - offsetof(UA_ResponseHeader, serviceResult) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StringTable") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ResponseHeader, stringTableSize) - offsetof(UA_ResponseHeader, serviceDiagnostics) - sizeof(UA_DiagnosticInfo), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AdditionalHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ResponseHeader, additionalHeader) - offsetof(UA_ResponseHeader, stringTable) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* VersionTime */
#define VersionTime_members NULL

/* ServiceFault */
static UA_DataTypeMember ServiceFault_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SessionlessInvokeRequestType */
static UA_DataTypeMember SessionlessInvokeRequestType_members[5] = {
{
    UA_TYPENAME("UrisVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NamespaceUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionlessInvokeRequestType, namespaceUrisSize) - offsetof(UA_SessionlessInvokeRequestType, urisVersion) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionlessInvokeRequestType, serverUrisSize) - offsetof(UA_SessionlessInvokeRequestType, namespaceUris) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionlessInvokeRequestType, localeIdsSize) - offsetof(UA_SessionlessInvokeRequestType, serverUris) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServiceId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionlessInvokeRequestType, serviceId) - offsetof(UA_SessionlessInvokeRequestType, localeIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SessionlessInvokeResponseType */
static UA_DataTypeMember SessionlessInvokeResponseType_members[3] = {
{
    UA_TYPENAME("NamespaceUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionlessInvokeResponseType, serverUrisSize) - offsetof(UA_SessionlessInvokeResponseType, namespaceUris) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServiceId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionlessInvokeResponseType, serviceId) - offsetof(UA_SessionlessInvokeResponseType, serverUris) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* FindServersRequest */
static UA_DataTypeMember FindServersRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersRequest, endpointUrl) - offsetof(UA_FindServersRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersRequest, localeIdsSize) - offsetof(UA_FindServersRequest, endpointUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersRequest, serverUrisSize) - offsetof(UA_FindServersRequest, localeIds) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* FindServersResponse */
static UA_DataTypeMember FindServersResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Servers") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_FindServersResponse, serversSize) - offsetof(UA_FindServersResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ServerOnNetwork */
static UA_DataTypeMember ServerOnNetwork_members[4] = {
{
    UA_TYPENAME("RecordId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ServerOnNetwork, serverName) - offsetof(UA_ServerOnNetwork, recordId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ServerOnNetwork, discoveryUrl) - offsetof(UA_ServerOnNetwork, serverName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCapabilities") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ServerOnNetwork, serverCapabilitiesSize) - offsetof(UA_ServerOnNetwork, discoveryUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* FindServersOnNetworkRequest */
static UA_DataTypeMember FindServersOnNetworkRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartingRecordId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_FindServersOnNetworkRequest, startingRecordId) - offsetof(UA_FindServersOnNetworkRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxRecordsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_FindServersOnNetworkRequest, maxRecordsToReturn) - offsetof(UA_FindServersOnNetworkRequest, startingRecordId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCapabilityFilter") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersOnNetworkRequest, serverCapabilityFilterSize) - offsetof(UA_FindServersOnNetworkRequest, maxRecordsToReturn) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* FindServersOnNetworkResponse */
static UA_DataTypeMember FindServersOnNetworkResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastCounterResetTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_FindServersOnNetworkResponse, lastCounterResetTime) - offsetof(UA_FindServersOnNetworkResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Servers") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVERONNETWORK], /* .memberType */
    offsetof(UA_FindServersOnNetworkResponse, serversSize) - offsetof(UA_FindServersOnNetworkResponse, lastCounterResetTime) - sizeof(UA_DateTime), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ApplicationInstanceCertificate */
#define ApplicationInstanceCertificate_members NULL

/* MessageSecurityMode */
static UA_DataTypeMember MessageSecurityMode_members[4] = {
{
    UA_TYPENAME("Invalid") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Sign") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("SignAndEncrypt") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* UserTokenType */
static UA_DataTypeMember UserTokenType_members[4] = {
{
    UA_TYPENAME("Anonymous") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("UserName") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Certificate") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("IssuedToken") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* UserTokenPolicy */
static UA_DataTypeMember UserTokenPolicy_members[5] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TokenType") /* .memberName */
    &UA_TYPES[UA_TYPES_USERTOKENTYPE], /* .memberType */
    offsetof(UA_UserTokenPolicy, tokenType) - offsetof(UA_UserTokenPolicy, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuedTokenType") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserTokenPolicy, issuedTokenType) - offsetof(UA_UserTokenPolicy, tokenType) - sizeof(UA_UserTokenType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuerEndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - offsetof(UA_UserTokenPolicy, issuedTokenType) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserTokenPolicy, securityPolicyUri) - offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EndpointDescription */
static UA_DataTypeMember EndpointDescription_members[8] = {
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Server") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_EndpointDescription, server) - offsetof(UA_EndpointDescription, endpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_EndpointDescription, serverCertificate) - offsetof(UA_EndpointDescription, server) - sizeof(UA_ApplicationDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_EndpointDescription, securityMode) - offsetof(UA_EndpointDescription, serverCertificate) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EndpointDescription, securityPolicyUri) - offsetof(UA_EndpointDescription, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserIdentityTokens") /* .memberName */
    &UA_TYPES[UA_TYPES_USERTOKENPOLICY], /* .memberType */
    offsetof(UA_EndpointDescription, userIdentityTokensSize) - offsetof(UA_EndpointDescription, securityPolicyUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EndpointDescription, transportProfileUri) - offsetof(UA_EndpointDescription, userIdentityTokens) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityLevel") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_EndpointDescription, securityLevel) - offsetof(UA_EndpointDescription, transportProfileUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* GetEndpointsRequest */
static UA_DataTypeMember GetEndpointsRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_GetEndpointsRequest, endpointUrl) - offsetof(UA_GetEndpointsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_GetEndpointsRequest, localeIdsSize) - offsetof(UA_GetEndpointsRequest, endpointUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProfileUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_GetEndpointsRequest, profileUrisSize) - offsetof(UA_GetEndpointsRequest, localeIds) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* GetEndpointsResponse */
static UA_DataTypeMember GetEndpointsResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Endpoints") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_GetEndpointsResponse, endpointsSize) - offsetof(UA_GetEndpointsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RegisteredServer */
static UA_DataTypeMember RegisteredServer_members[8] = {
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProductUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, productUri) - offsetof(UA_RegisteredServer, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNames") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_RegisteredServer, serverNamesSize) - offsetof(UA_RegisteredServer, productUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerType") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONTYPE], /* .memberType */
    offsetof(UA_RegisteredServer, serverType) - offsetof(UA_RegisteredServer, serverNames) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GatewayServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, gatewayServerUri) - offsetof(UA_RegisteredServer, serverType) - sizeof(UA_ApplicationType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryUrls") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, discoveryUrlsSize) - offsetof(UA_RegisteredServer, gatewayServerUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SemaphoreFilePath") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, semaphoreFilePath) - offsetof(UA_RegisteredServer, discoveryUrls) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsOnline") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_RegisteredServer, isOnline) - offsetof(UA_RegisteredServer, semaphoreFilePath) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* RegisterServerRequest */
static UA_DataTypeMember RegisterServerRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Server") /* .memberName */
    &UA_TYPES[UA_TYPES_REGISTEREDSERVER], /* .memberType */
    offsetof(UA_RegisterServerRequest, server) - offsetof(UA_RegisterServerRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* RegisterServerResponse */
static UA_DataTypeMember RegisterServerResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* MdnsDiscoveryConfiguration */
static UA_DataTypeMember MdnsDiscoveryConfiguration_members[2] = {
{
    UA_TYPENAME("MdnsServerName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCapabilities") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_MdnsDiscoveryConfiguration, serverCapabilitiesSize) - offsetof(UA_MdnsDiscoveryConfiguration, mdnsServerName) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RegisterServer2Request */
static UA_DataTypeMember RegisterServer2Request_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Server") /* .memberName */
    &UA_TYPES[UA_TYPES_REGISTEREDSERVER], /* .memberType */
    offsetof(UA_RegisterServer2Request, server) - offsetof(UA_RegisterServer2Request, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_RegisterServer2Request, discoveryConfigurationSize) - offsetof(UA_RegisterServer2Request, server) - sizeof(UA_RegisteredServer), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RegisterServer2Response */
static UA_DataTypeMember RegisterServer2Response_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConfigurationResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_RegisterServer2Response, configurationResultsSize) - offsetof(UA_RegisterServer2Response, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_RegisterServer2Response, diagnosticInfosSize) - offsetof(UA_RegisterServer2Response, configurationResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SecurityTokenRequestType */
static UA_DataTypeMember SecurityTokenRequestType_members[2] = {
{
    UA_TYPENAME("Issue") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Renew") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ChannelSecurityToken */
static UA_DataTypeMember ChannelSecurityToken_members[4] = {
{
    UA_TYPENAME("ChannelId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TokenId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ChannelSecurityToken, tokenId) - offsetof(UA_ChannelSecurityToken, channelId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreatedAt") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ChannelSecurityToken, createdAt) - offsetof(UA_ChannelSecurityToken, tokenId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedLifetime") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ChannelSecurityToken, revisedLifetime) - offsetof(UA_ChannelSecurityToken, createdAt) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* OpenSecureChannelRequest */
static UA_DataTypeMember OpenSecureChannelRequest_members[6] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - offsetof(UA_OpenSecureChannelRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestType") /* .memberName */
    &UA_TYPES[UA_TYPES_SECURITYTOKENREQUESTTYPE], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, requestType) - offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, securityMode) - offsetof(UA_OpenSecureChannelRequest, requestType) - sizeof(UA_SecurityTokenRequestType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, clientNonce) - offsetof(UA_OpenSecureChannelRequest, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedLifetime") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, requestedLifetime) - offsetof(UA_OpenSecureChannelRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* OpenSecureChannelResponse */
static UA_DataTypeMember OpenSecureChannelResponse_members[4] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - offsetof(UA_OpenSecureChannelResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityToken") /* .memberName */
    &UA_TYPES[UA_TYPES_CHANNELSECURITYTOKEN], /* .memberType */
    offsetof(UA_OpenSecureChannelResponse, securityToken) - offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_OpenSecureChannelResponse, serverNonce) - offsetof(UA_OpenSecureChannelResponse, securityToken) - sizeof(UA_ChannelSecurityToken), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CloseSecureChannelRequest */
static UA_DataTypeMember CloseSecureChannelRequest_members[1] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CloseSecureChannelResponse */
static UA_DataTypeMember CloseSecureChannelResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SignedSoftwareCertificate */
static UA_DataTypeMember SignedSoftwareCertificate_members[2] = {
{
    UA_TYPENAME("CertificateData") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Signature") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_SignedSoftwareCertificate, signature) - offsetof(UA_SignedSoftwareCertificate, certificateData) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SessionAuthenticationToken */
#define SessionAuthenticationToken_members NULL

/* SignatureData */
static UA_DataTypeMember SignatureData_members[2] = {
{
    UA_TYPENAME("Algorithm") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Signature") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_SignatureData, signature) - offsetof(UA_SignatureData, algorithm) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CreateSessionRequest */
static UA_DataTypeMember CreateSessionRequest_members[9] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientDescription") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_CreateSessionRequest, clientDescription) - offsetof(UA_CreateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, serverUri) - offsetof(UA_CreateSessionRequest, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, endpointUrl) - offsetof(UA_CreateSessionRequest, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, sessionName) - offsetof(UA_CreateSessionRequest, endpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, clientNonce) - offsetof(UA_CreateSessionRequest, sessionName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, clientCertificate) - offsetof(UA_CreateSessionRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedSessionTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - offsetof(UA_CreateSessionRequest, clientCertificate) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxResponseMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSessionRequest, maxResponseMessageSize) - offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CreateSessionResponse */
static UA_DataTypeMember CreateSessionResponse_members[10] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_CreateSessionResponse, sessionId) - offsetof(UA_CreateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationToken") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_CreateSessionResponse, authenticationToken) - offsetof(UA_CreateSessionResponse, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedSessionTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - offsetof(UA_CreateSessionResponse, authenticationToken) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverNonce) - offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverCertificate) - offsetof(UA_CreateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerEndpoints") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverEndpointsSize) - offsetof(UA_CreateSessionResponse, serverCertificate) - sizeof(UA_ByteString), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerSoftwareCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverSoftwareCertificatesSize) - offsetof(UA_CreateSessionResponse, serverEndpoints) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerSignature") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverSignature) - offsetof(UA_CreateSessionResponse, serverSoftwareCertificates) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxRequestMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSessionResponse, maxRequestMessageSize) - offsetof(UA_CreateSessionResponse, serverSignature) - sizeof(UA_SignatureData), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* UserIdentityToken */
static UA_DataTypeMember UserIdentityToken_members[1] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AnonymousIdentityToken */
static UA_DataTypeMember AnonymousIdentityToken_members[1] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* UserNameIdentityToken */
static UA_DataTypeMember UserNameIdentityToken_members[4] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserNameIdentityToken, userName) - offsetof(UA_UserNameIdentityToken, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Password") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_UserNameIdentityToken, password) - offsetof(UA_UserNameIdentityToken, userName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EncryptionAlgorithm") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserNameIdentityToken, encryptionAlgorithm) - offsetof(UA_UserNameIdentityToken, password) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* X509IdentityToken */
static UA_DataTypeMember X509IdentityToken_members[2] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CertificateData") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_X509IdentityToken, certificateData) - offsetof(UA_X509IdentityToken, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* IssuedIdentityToken */
static UA_DataTypeMember IssuedIdentityToken_members[3] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TokenData") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_IssuedIdentityToken, tokenData) - offsetof(UA_IssuedIdentityToken, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EncryptionAlgorithm") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_IssuedIdentityToken, encryptionAlgorithm) - offsetof(UA_IssuedIdentityToken, tokenData) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* RsaEncryptedSecret */
#define RsaEncryptedSecret_members NULL

/* EccEncryptedSecret */
#define EccEncryptedSecret_members NULL

/* ActivateSessionRequest */
static UA_DataTypeMember ActivateSessionRequest_members[6] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientSignature") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */
    offsetof(UA_ActivateSessionRequest, clientSignature) - offsetof(UA_ActivateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientSoftwareCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */
    offsetof(UA_ActivateSessionRequest, clientSoftwareCertificatesSize) - offsetof(UA_ActivateSessionRequest, clientSignature) - sizeof(UA_SignatureData), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ActivateSessionRequest, localeIdsSize) - offsetof(UA_ActivateSessionRequest, clientSoftwareCertificates) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserIdentityToken") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ActivateSessionRequest, userIdentityToken) - offsetof(UA_ActivateSessionRequest, localeIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserTokenSignature") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */
    offsetof(UA_ActivateSessionRequest, userTokenSignature) - offsetof(UA_ActivateSessionRequest, userIdentityToken) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ActivateSessionResponse */
static UA_DataTypeMember ActivateSessionResponse_members[4] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_ActivateSessionResponse, serverNonce) - offsetof(UA_ActivateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ActivateSessionResponse, resultsSize) - offsetof(UA_ActivateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ActivateSessionResponse, diagnosticInfosSize) - offsetof(UA_ActivateSessionResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* CloseSessionRequest */
static UA_DataTypeMember CloseSessionRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteSubscriptions") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_CloseSessionRequest, deleteSubscriptions) - offsetof(UA_CloseSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CloseSessionResponse */
static UA_DataTypeMember CloseSessionResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CancelRequest */
static UA_DataTypeMember CancelRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CancelRequest, requestHandle) - offsetof(UA_CancelRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CancelResponse */
static UA_DataTypeMember CancelResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CancelCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CancelResponse, cancelCount) - offsetof(UA_CancelResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* NodeAttributesMask */
static UA_DataTypeMember NodeAttributesMask_members[35] = {
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("AccessLevel") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("BrowseName") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ContainsNoLoops") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("EventNotifier") /* .memberName */
    (const UA_DataType *)8, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Executable") /* .memberName */
    (const UA_DataType *)9, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Historizing") /* .memberName */
    (const UA_DataType *)10, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("InverseName") /* .memberName */
    (const UA_DataType *)11, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    (const UA_DataType *)12, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("MinimumSamplingInterval") /* .memberName */
    (const UA_DataType *)13, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("NodeClass") /* .memberName */
    (const UA_DataType *)14, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("NodeId") /* .memberName */
    (const UA_DataType *)15, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Symmetric") /* .memberName */
    (const UA_DataType *)16, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("UserAccessLevel") /* .memberName */
    (const UA_DataType *)17, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("UserExecutable") /* .memberName */
    (const UA_DataType *)18, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    (const UA_DataType *)19, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    (const UA_DataType *)20, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    (const UA_DataType *)21, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    (const UA_DataType *)22, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("DataTypeDefinition") /* .memberName */
    (const UA_DataType *)23, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("RolePermissions") /* .memberName */
    (const UA_DataType *)24, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("AccessRestrictions") /* .memberName */
    (const UA_DataType *)25, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("All") /* .memberName */
    (const UA_DataType *)26, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("BaseNode") /* .memberName */
    (const UA_DataType *)27, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Object") /* .memberName */
    (const UA_DataType *)28, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ObjectType") /* .memberName */
    (const UA_DataType *)29, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Variable") /* .memberName */
    (const UA_DataType *)30, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("VariableType") /* .memberName */
    (const UA_DataType *)31, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Method") /* .memberName */
    (const UA_DataType *)32, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ReferenceType") /* .memberName */
    (const UA_DataType *)33, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("View") /* .memberName */
    (const UA_DataType *)34, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* NodeAttributes */
static UA_DataTypeMember NodeAttributes_members[5] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_NodeAttributes, displayName) - offsetof(UA_NodeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_NodeAttributes, description) - offsetof(UA_NodeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_NodeAttributes, writeMask) - offsetof(UA_NodeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_NodeAttributes, userWriteMask) - offsetof(UA_NodeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ObjectAttributes */
static UA_DataTypeMember ObjectAttributes_members[6] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectAttributes, displayName) - offsetof(UA_ObjectAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectAttributes, description) - offsetof(UA_ObjectAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectAttributes, writeMask) - offsetof(UA_ObjectAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectAttributes, userWriteMask) - offsetof(UA_ObjectAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventNotifier") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_ObjectAttributes, eventNotifier) - offsetof(UA_ObjectAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* VariableAttributes */
static UA_DataTypeMember VariableAttributes_members[13] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableAttributes, displayName) - offsetof(UA_VariableAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableAttributes, description) - offsetof(UA_VariableAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableAttributes, writeMask) - offsetof(UA_VariableAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableAttributes, userWriteMask) - offsetof(UA_VariableAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_VariableAttributes, value) - offsetof(UA_VariableAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_VariableAttributes, dataType) - offsetof(UA_VariableAttributes, value) - sizeof(UA_Variant), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_VariableAttributes, valueRank) - offsetof(UA_VariableAttributes, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableAttributes, arrayDimensionsSize) - offsetof(UA_VariableAttributes, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AccessLevel") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_VariableAttributes, accessLevel) - offsetof(UA_VariableAttributes, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserAccessLevel") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_VariableAttributes, userAccessLevel) - offsetof(UA_VariableAttributes, accessLevel) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MinimumSamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_VariableAttributes, minimumSamplingInterval) - offsetof(UA_VariableAttributes, userAccessLevel) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Historizing") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_VariableAttributes, historizing) - offsetof(UA_VariableAttributes, minimumSamplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* MethodAttributes */
static UA_DataTypeMember MethodAttributes_members[7] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_MethodAttributes, displayName) - offsetof(UA_MethodAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_MethodAttributes, description) - offsetof(UA_MethodAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MethodAttributes, writeMask) - offsetof(UA_MethodAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MethodAttributes, userWriteMask) - offsetof(UA_MethodAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Executable") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_MethodAttributes, executable) - offsetof(UA_MethodAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserExecutable") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_MethodAttributes, userExecutable) - offsetof(UA_MethodAttributes, executable) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ObjectTypeAttributes */
static UA_DataTypeMember ObjectTypeAttributes_members[6] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, displayName) - offsetof(UA_ObjectTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, description) - offsetof(UA_ObjectTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, writeMask) - offsetof(UA_ObjectTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, userWriteMask) - offsetof(UA_ObjectTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, isAbstract) - offsetof(UA_ObjectTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* VariableTypeAttributes */
static UA_DataTypeMember VariableTypeAttributes_members[10] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableTypeAttributes, displayName) - offsetof(UA_VariableTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableTypeAttributes, description) - offsetof(UA_VariableTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, writeMask) - offsetof(UA_VariableTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, userWriteMask) - offsetof(UA_VariableTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_VariableTypeAttributes, value) - offsetof(UA_VariableTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_VariableTypeAttributes, dataType) - offsetof(UA_VariableTypeAttributes, value) - sizeof(UA_Variant), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, valueRank) - offsetof(UA_VariableTypeAttributes, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, arrayDimensionsSize) - offsetof(UA_VariableTypeAttributes, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_VariableTypeAttributes, isAbstract) - offsetof(UA_VariableTypeAttributes, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ReferenceTypeAttributes */
static UA_DataTypeMember ReferenceTypeAttributes_members[8] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, displayName) - offsetof(UA_ReferenceTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, description) - offsetof(UA_ReferenceTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, writeMask) - offsetof(UA_ReferenceTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, userWriteMask) - offsetof(UA_ReferenceTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, isAbstract) - offsetof(UA_ReferenceTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Symmetric") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, symmetric) - offsetof(UA_ReferenceTypeAttributes, isAbstract) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InverseName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, inverseName) - offsetof(UA_ReferenceTypeAttributes, symmetric) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DataTypeAttributes */
static UA_DataTypeMember DataTypeAttributes_members[6] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_DataTypeAttributes, displayName) - offsetof(UA_DataTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_DataTypeAttributes, description) - offsetof(UA_DataTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataTypeAttributes, writeMask) - offsetof(UA_DataTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataTypeAttributes, userWriteMask) - offsetof(UA_DataTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DataTypeAttributes, isAbstract) - offsetof(UA_DataTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ViewAttributes */
static UA_DataTypeMember ViewAttributes_members[7] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ViewAttributes, displayName) - offsetof(UA_ViewAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ViewAttributes, description) - offsetof(UA_ViewAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ViewAttributes, writeMask) - offsetof(UA_ViewAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ViewAttributes, userWriteMask) - offsetof(UA_ViewAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContainsNoLoops") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ViewAttributes, containsNoLoops) - offsetof(UA_ViewAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventNotifier") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_ViewAttributes, eventNotifier) - offsetof(UA_ViewAttributes, containsNoLoops) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* GenericAttributeValue */
static UA_DataTypeMember GenericAttributeValue_members[2] = {
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_GenericAttributeValue, value) - offsetof(UA_GenericAttributeValue, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* GenericAttributes */
static UA_DataTypeMember GenericAttributes_members[6] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_GenericAttributes, displayName) - offsetof(UA_GenericAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_GenericAttributes, description) - offsetof(UA_GenericAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_GenericAttributes, writeMask) - offsetof(UA_GenericAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_GenericAttributes, userWriteMask) - offsetof(UA_GenericAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeValues") /* .memberName */
    &UA_TYPES[UA_TYPES_GENERICATTRIBUTEVALUE], /* .memberType */
    offsetof(UA_GenericAttributes, attributeValuesSize) - offsetof(UA_GenericAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* AddNodesItem */
static UA_DataTypeMember AddNodesItem_members[7] = {
{
    UA_TYPENAME("ParentNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AddNodesItem, referenceTypeId) - offsetof(UA_AddNodesItem, parentNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedNewNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_AddNodesItem, requestedNewNodeId) - offsetof(UA_AddNodesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseName") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_AddNodesItem, browseName) - offsetof(UA_AddNodesItem, requestedNewNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeClass") /* .memberName */
    &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */
    offsetof(UA_AddNodesItem, nodeClass) - offsetof(UA_AddNodesItem, browseName) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_AddNodesItem, nodeAttributes) - offsetof(UA_AddNodesItem, nodeClass) - sizeof(UA_NodeClass), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TypeDefinition") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_AddNodesItem, typeDefinition) - offsetof(UA_AddNodesItem, nodeAttributes) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AddNodesResult */
static UA_DataTypeMember AddNodesResult_members[2] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddedNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AddNodesResult, addedNodeId) - offsetof(UA_AddNodesResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AddNodesRequest */
static UA_DataTypeMember AddNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToAdd") /* .memberName */
    &UA_TYPES[UA_TYPES_ADDNODESITEM], /* .memberType */
    offsetof(UA_AddNodesRequest, nodesToAddSize) - offsetof(UA_AddNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* AddNodesResponse */
static UA_DataTypeMember AddNodesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_ADDNODESRESULT], /* .memberType */
    offsetof(UA_AddNodesResponse, resultsSize) - offsetof(UA_AddNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_AddNodesResponse, diagnosticInfosSize) - offsetof(UA_AddNodesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* AddReferencesItem */
static UA_DataTypeMember AddReferencesItem_members[6] = {
{
    UA_TYPENAME("SourceNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AddReferencesItem, referenceTypeId) - offsetof(UA_AddReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_AddReferencesItem, isForward) - offsetof(UA_AddReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_AddReferencesItem, targetServerUri) - offsetof(UA_AddReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_AddReferencesItem, targetNodeId) - offsetof(UA_AddReferencesItem, targetServerUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetNodeClass") /* .memberName */
    &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */
    offsetof(UA_AddReferencesItem, targetNodeClass) - offsetof(UA_AddReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AddReferencesRequest */
static UA_DataTypeMember AddReferencesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferencesToAdd") /* .memberName */
    &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], /* .memberType */
    offsetof(UA_AddReferencesRequest, referencesToAddSize) - offsetof(UA_AddReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* AddReferencesResponse */
static UA_DataTypeMember AddReferencesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_AddReferencesResponse, resultsSize) - offsetof(UA_AddReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_AddReferencesResponse, diagnosticInfosSize) - offsetof(UA_AddReferencesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteNodesItem */
static UA_DataTypeMember DeleteNodesItem_members[2] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteTargetReferences") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteNodesItem, deleteTargetReferences) - offsetof(UA_DeleteNodesItem, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteNodesRequest */
static UA_DataTypeMember DeleteNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToDelete") /* .memberName */
    &UA_TYPES[UA_TYPES_DELETENODESITEM], /* .memberType */
    offsetof(UA_DeleteNodesRequest, nodesToDeleteSize) - offsetof(UA_DeleteNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteNodesResponse */
static UA_DataTypeMember DeleteNodesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteNodesResponse, resultsSize) - offsetof(UA_DeleteNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteNodesResponse, diagnosticInfosSize) - offsetof(UA_DeleteNodesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteReferencesItem */
static UA_DataTypeMember DeleteReferencesItem_members[5] = {
{
    UA_TYPENAME("SourceNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_DeleteReferencesItem, referenceTypeId) - offsetof(UA_DeleteReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteReferencesItem, isForward) - offsetof(UA_DeleteReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_DeleteReferencesItem, targetNodeId) - offsetof(UA_DeleteReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteBidirectional") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteReferencesItem, deleteBidirectional) - offsetof(UA_DeleteReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteReferencesRequest */
static UA_DataTypeMember DeleteReferencesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferencesToDelete") /* .memberName */
    &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], /* .memberType */
    offsetof(UA_DeleteReferencesRequest, referencesToDeleteSize) - offsetof(UA_DeleteReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteReferencesResponse */
static UA_DataTypeMember DeleteReferencesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteReferencesResponse, resultsSize) - offsetof(UA_DeleteReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteReferencesResponse, diagnosticInfosSize) - offsetof(UA_DeleteReferencesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* AttributeWriteMask */
#define AttributeWriteMask_members NULL

/* BrowseDirection */
static UA_DataTypeMember BrowseDirection_members[4] = {
{
    UA_TYPENAME("Forward") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Inverse") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Both") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Invalid") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ViewDescription */
static UA_DataTypeMember ViewDescription_members[3] = {
{
    UA_TYPENAME("ViewId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Timestamp") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ViewDescription, timestamp) - offsetof(UA_ViewDescription, viewId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ViewVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ViewDescription, viewVersion) - offsetof(UA_ViewDescription, timestamp) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrowseDescription */
static UA_DataTypeMember BrowseDescription_members[6] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseDirection") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEDIRECTION], /* .memberType */
    offsetof(UA_BrowseDescription, browseDirection) - offsetof(UA_BrowseDescription, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_BrowseDescription, referenceTypeId) - offsetof(UA_BrowseDescription, browseDirection) - sizeof(UA_BrowseDirection), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IncludeSubtypes") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_BrowseDescription, includeSubtypes) - offsetof(UA_BrowseDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeClassMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowseDescription, nodeClassMask) - offsetof(UA_BrowseDescription, includeSubtypes) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ResultMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowseDescription, resultMask) - offsetof(UA_BrowseDescription, nodeClassMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrowseResultMask */
static UA_DataTypeMember BrowseResultMask_members[10] = {
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("NodeClass") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("BrowseName") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("TypeDefinition") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("All") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeInfo") /* .memberName */
    (const UA_DataType *)8, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("TargetInfo") /* .memberName */
    (const UA_DataType *)9, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ReferenceDescription */
static UA_DataTypeMember ReferenceDescription_members[7] = {
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReferenceDescription, isForward) - offsetof(UA_ReferenceDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_ReferenceDescription, nodeId) - offsetof(UA_ReferenceDescription, isForward) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseName") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_ReferenceDescription, browseName) - offsetof(UA_ReferenceDescription, nodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceDescription, displayName) - offsetof(UA_ReferenceDescription, browseName) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeClass") /* .memberName */
    &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */
    offsetof(UA_ReferenceDescription, nodeClass) - offsetof(UA_ReferenceDescription, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TypeDefinition") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_ReferenceDescription, typeDefinition) - offsetof(UA_ReferenceDescription, nodeClass) - sizeof(UA_NodeClass), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ContinuationPoint */
#define ContinuationPoint_members NULL

/* BrowseResult */
static UA_DataTypeMember BrowseResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_BrowseResult, continuationPoint) - offsetof(UA_BrowseResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("References") /* .memberName */
    &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], /* .memberType */
    offsetof(UA_BrowseResult, referencesSize) - offsetof(UA_BrowseResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* BrowseRequest */
static UA_DataTypeMember BrowseRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("View") /* .memberName */
    &UA_TYPES[UA_TYPES_VIEWDESCRIPTION], /* .memberType */
    offsetof(UA_BrowseRequest, view) - offsetof(UA_BrowseRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedMaxReferencesPerNode") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - offsetof(UA_BrowseRequest, view) - sizeof(UA_ViewDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToBrowse") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], /* .memberType */
    offsetof(UA_BrowseRequest, nodesToBrowseSize) - offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* BrowseResponse */
static UA_DataTypeMember BrowseResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */
    offsetof(UA_BrowseResponse, resultsSize) - offsetof(UA_BrowseResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_BrowseResponse, diagnosticInfosSize) - offsetof(UA_BrowseResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* BrowseNextRequest */
static UA_DataTypeMember BrowseNextRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReleaseContinuationPoints") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - offsetof(UA_BrowseNextRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoints") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_BrowseNextRequest, continuationPointsSize) - offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* BrowseNextResponse */
static UA_DataTypeMember BrowseNextResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */
    offsetof(UA_BrowseNextResponse, resultsSize) - offsetof(UA_BrowseNextResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_BrowseNextResponse, diagnosticInfosSize) - offsetof(UA_BrowseNextResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RelativePathElement */
static UA_DataTypeMember RelativePathElement_members[4] = {
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsInverse") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_RelativePathElement, isInverse) - offsetof(UA_RelativePathElement, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IncludeSubtypes") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_RelativePathElement, includeSubtypes) - offsetof(UA_RelativePathElement, isInverse) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetName") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_RelativePathElement, targetName) - offsetof(UA_RelativePathElement, includeSubtypes) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* RelativePath */
static UA_DataTypeMember RelativePath_members[1] = {
{
    UA_TYPENAME("Elements") /* .memberName */
    &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* BrowsePath */
static UA_DataTypeMember BrowsePath_members[2] = {
{
    UA_TYPENAME("StartingNode") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RelativePath") /* .memberName */
    &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */
    offsetof(UA_BrowsePath, relativePath) - offsetof(UA_BrowsePath, startingNode) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrowsePathTarget */
static UA_DataTypeMember BrowsePathTarget_members[2] = {
{
    UA_TYPENAME("TargetId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RemainingPathIndex") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowsePathTarget, remainingPathIndex) - offsetof(UA_BrowsePathTarget, targetId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* BrowsePathResult */
static UA_DataTypeMember BrowsePathResult_members[2] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Targets") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], /* .memberType */
    offsetof(UA_BrowsePathResult, targetsSize) - offsetof(UA_BrowsePathResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* TranslateBrowsePathsToNodeIdsRequest */
static UA_DataTypeMember TranslateBrowsePathsToNodeIdsRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowsePaths") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEPATH], /* .memberType */
    offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, browsePathsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* TranslateBrowsePathsToNodeIdsResponse */
static UA_DataTypeMember TranslateBrowsePathsToNodeIdsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEPATHRESULT], /* .memberType */
    offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, resultsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, diagnosticInfosSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RegisterNodesRequest */
static UA_DataTypeMember RegisterNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToRegister") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_RegisterNodesRequest, nodesToRegisterSize) - offsetof(UA_RegisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RegisterNodesResponse */
static UA_DataTypeMember RegisterNodesResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RegisteredNodeIds") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_RegisterNodesResponse, registeredNodeIdsSize) - offsetof(UA_RegisterNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* UnregisterNodesRequest */
static UA_DataTypeMember UnregisterNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToUnregister") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_UnregisterNodesRequest, nodesToUnregisterSize) - offsetof(UA_UnregisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* UnregisterNodesResponse */
static UA_DataTypeMember UnregisterNodesResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* Counter */
#define Counter_members NULL

/* OpaqueNumericRange */
#define OpaqueNumericRange_members NULL

/* EndpointConfiguration */
static UA_DataTypeMember EndpointConfiguration_members[9] = {
{
    UA_TYPENAME("OperationTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UseBinaryEncoding") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_EndpointConfiguration, useBinaryEncoding) - offsetof(UA_EndpointConfiguration, operationTimeout) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxStringLength") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EndpointConfiguration, maxStringLength) - offsetof(UA_EndpointConfiguration, useBinaryEncoding) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxByteStringLength") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EndpointConfiguration, maxByteStringLength) - offsetof(UA_EndpointConfiguration, maxStringLength) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxArrayLength") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EndpointConfiguration, maxArrayLength) - offsetof(UA_EndpointConfiguration, maxByteStringLength) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EndpointConfiguration, maxMessageSize) - offsetof(UA_EndpointConfiguration, maxArrayLength) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EndpointConfiguration, maxBufferSize) - offsetof(UA_EndpointConfiguration, maxMessageSize) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ChannelLifetime") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EndpointConfiguration, channelLifetime) - offsetof(UA_EndpointConfiguration, maxBufferSize) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityTokenLifetime") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EndpointConfiguration, securityTokenLifetime) - offsetof(UA_EndpointConfiguration, channelLifetime) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* QueryDataDescription */
static UA_DataTypeMember QueryDataDescription_members[3] = {
{
    UA_TYPENAME("RelativePath") /* .memberName */
    &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_QueryDataDescription, attributeId) - offsetof(UA_QueryDataDescription, relativePath) - sizeof(UA_RelativePath), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_QueryDataDescription, indexRange) - offsetof(UA_QueryDataDescription, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* NodeTypeDescription */
static UA_DataTypeMember NodeTypeDescription_members[3] = {
{
    UA_TYPENAME("TypeDefinitionNode") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IncludeSubTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_NodeTypeDescription, includeSubTypes) - offsetof(UA_NodeTypeDescription, typeDefinitionNode) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_QUERYDATADESCRIPTION], /* .memberType */
    offsetof(UA_NodeTypeDescription, dataToReturnSize) - offsetof(UA_NodeTypeDescription, includeSubTypes) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* FilterOperator */
static UA_DataTypeMember FilterOperator_members[18] = {
{
    UA_TYPENAME("Equals") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("IsNull") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("GreaterThan") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("LessThan") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("GreaterThanOrEqual") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("LessThanOrEqual") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Like") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Not") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Between") /* .memberName */
    (const UA_DataType *)8, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("InList") /* .memberName */
    (const UA_DataType *)9, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("And") /* .memberName */
    (const UA_DataType *)10, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Or") /* .memberName */
    (const UA_DataType *)11, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Cast") /* .memberName */
    (const UA_DataType *)12, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("InView") /* .memberName */
    (const UA_DataType *)13, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("OfType") /* .memberName */
    (const UA_DataType *)14, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("RelatedTo") /* .memberName */
    (const UA_DataType *)15, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("BitwiseAnd") /* .memberName */
    (const UA_DataType *)16, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("BitwiseOr") /* .memberName */
    (const UA_DataType *)17, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* QueryDataSet */
static UA_DataTypeMember QueryDataSet_members[3] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TypeDefinitionNode") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_QueryDataSet, typeDefinitionNode) - offsetof(UA_QueryDataSet, nodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Values") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_QueryDataSet, valuesSize) - offsetof(UA_QueryDataSet, typeDefinitionNode) - sizeof(UA_ExpandedNodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* NodeReference */
static UA_DataTypeMember NodeReference_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_NodeReference, referenceTypeId) - offsetof(UA_NodeReference, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_NodeReference, isForward) - offsetof(UA_NodeReference, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferencedNodeIds") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_NodeReference, referencedNodeIdsSize) - offsetof(UA_NodeReference, isForward) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ContentFilterElement */
static UA_DataTypeMember ContentFilterElement_members[2] = {
{
    UA_TYPENAME("FilterOperator") /* .memberName */
    &UA_TYPES[UA_TYPES_FILTEROPERATOR], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FilterOperands") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ContentFilterElement, filterOperandsSize) - offsetof(UA_ContentFilterElement, filterOperator) - sizeof(UA_FilterOperator), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ContentFilter */
static UA_DataTypeMember ContentFilter_members[1] = {
{
    UA_TYPENAME("Elements") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ElementOperand */
static UA_DataTypeMember ElementOperand_members[1] = {
{
    UA_TYPENAME("Index") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* LiteralOperand */
static UA_DataTypeMember LiteralOperand_members[1] = {
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AttributeOperand */
static UA_DataTypeMember AttributeOperand_members[5] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Alias") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_AttributeOperand, alias) - offsetof(UA_AttributeOperand, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowsePath") /* .memberName */
    &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */
    offsetof(UA_AttributeOperand, browsePath) - offsetof(UA_AttributeOperand, alias) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_AttributeOperand, attributeId) - offsetof(UA_AttributeOperand, browsePath) - sizeof(UA_RelativePath), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_AttributeOperand, indexRange) - offsetof(UA_AttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SimpleAttributeOperand */
static UA_DataTypeMember SimpleAttributeOperand_members[4] = {
{
    UA_TYPENAME("TypeDefinitionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowsePath") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_SimpleAttributeOperand, browsePathSize) - offsetof(UA_SimpleAttributeOperand, typeDefinitionId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SimpleAttributeOperand, attributeId) - offsetof(UA_SimpleAttributeOperand, browsePath) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SimpleAttributeOperand, indexRange) - offsetof(UA_SimpleAttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ContentFilterElementResult */
static UA_DataTypeMember ContentFilterElementResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OperandStatusCodes") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ContentFilterElementResult, operandStatusCodesSize) - offsetof(UA_ContentFilterElementResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OperandDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ContentFilterElementResult, operandDiagnosticInfosSize) - offsetof(UA_ContentFilterElementResult, operandStatusCodes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ContentFilterResult */
static UA_DataTypeMember ContentFilterResult_members[2] = {
{
    UA_TYPENAME("ElementResults") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ElementDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ContentFilterResult, elementDiagnosticInfosSize) - offsetof(UA_ContentFilterResult, elementResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ParsingResult */
static UA_DataTypeMember ParsingResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataStatusCodes") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ParsingResult, dataStatusCodesSize) - offsetof(UA_ParsingResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ParsingResult, dataDiagnosticInfosSize) - offsetof(UA_ParsingResult, dataStatusCodes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* QueryFirstRequest */
static UA_DataTypeMember QueryFirstRequest_members[6] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("View") /* .memberName */
    &UA_TYPES[UA_TYPES_VIEWDESCRIPTION], /* .memberType */
    offsetof(UA_QueryFirstRequest, view) - offsetof(UA_QueryFirstRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_NODETYPEDESCRIPTION], /* .memberType */
    offsetof(UA_QueryFirstRequest, nodeTypesSize) - offsetof(UA_QueryFirstRequest, view) - sizeof(UA_ViewDescription), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Filter") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTER], /* .memberType */
    offsetof(UA_QueryFirstRequest, filter) - offsetof(UA_QueryFirstRequest, nodeTypes) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxDataSetsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_QueryFirstRequest, maxDataSetsToReturn) - offsetof(UA_QueryFirstRequest, filter) - sizeof(UA_ContentFilter), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxReferencesToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_QueryFirstRequest, maxReferencesToReturn) - offsetof(UA_QueryFirstRequest, maxDataSetsToReturn) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* QueryFirstResponse */
static UA_DataTypeMember QueryFirstResponse_members[6] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueryDataSets") /* .memberName */
    &UA_TYPES[UA_TYPES_QUERYDATASET], /* .memberType */
    offsetof(UA_QueryFirstResponse, queryDataSetsSize) - offsetof(UA_QueryFirstResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_QueryFirstResponse, continuationPoint) - offsetof(UA_QueryFirstResponse, queryDataSets) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ParsingResults") /* .memberName */
    &UA_TYPES[UA_TYPES_PARSINGRESULT], /* .memberType */
    offsetof(UA_QueryFirstResponse, parsingResultsSize) - offsetof(UA_QueryFirstResponse, continuationPoint) - sizeof(UA_ByteString), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_QueryFirstResponse, diagnosticInfosSize) - offsetof(UA_QueryFirstResponse, parsingResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FilterResult") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT], /* .memberType */
    offsetof(UA_QueryFirstResponse, filterResult) - offsetof(UA_QueryFirstResponse, diagnosticInfos) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* QueryNextRequest */
static UA_DataTypeMember QueryNextRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReleaseContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_QueryNextRequest, releaseContinuationPoint) - offsetof(UA_QueryNextRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_QueryNextRequest, continuationPoint) - offsetof(UA_QueryNextRequest, releaseContinuationPoint) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* QueryNextResponse */
static UA_DataTypeMember QueryNextResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueryDataSets") /* .memberName */
    &UA_TYPES[UA_TYPES_QUERYDATASET], /* .memberType */
    offsetof(UA_QueryNextResponse, queryDataSetsSize) - offsetof(UA_QueryNextResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_QueryNextResponse, revisedContinuationPoint) - offsetof(UA_QueryNextResponse, queryDataSets) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TimestampsToReturn */
static UA_DataTypeMember TimestampsToReturn_members[5] = {
{
    UA_TYPENAME("Source") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Server") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Both") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Neither") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Invalid") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ReadValueId */
static UA_DataTypeMember ReadValueId_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReadValueId, attributeId) - offsetof(UA_ReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ReadValueId, indexRange) - offsetof(UA_ReadValueId, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataEncoding") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_ReadValueId, dataEncoding) - offsetof(UA_ReadValueId, indexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ReadRequest */
static UA_DataTypeMember ReadRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxAge") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ReadRequest, maxAge) - offsetof(UA_ReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_ReadRequest, timestampsToReturn) - offsetof(UA_ReadRequest, maxAge) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToRead") /* .memberName */
    &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */
    offsetof(UA_ReadRequest, nodesToReadSize) - offsetof(UA_ReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ReadResponse */
static UA_DataTypeMember ReadResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_ReadResponse, resultsSize) - offsetof(UA_ReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ReadResponse, diagnosticInfosSize) - offsetof(UA_ReadResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryReadValueId */
static UA_DataTypeMember HistoryReadValueId_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_HistoryReadValueId, indexRange) - offsetof(UA_HistoryReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataEncoding") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_HistoryReadValueId, dataEncoding) - offsetof(UA_HistoryReadValueId, indexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_HistoryReadValueId, continuationPoint) - offsetof(UA_HistoryReadValueId, dataEncoding) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryReadResult */
static UA_DataTypeMember HistoryReadResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_HistoryReadResult, continuationPoint) - offsetof(UA_HistoryReadResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryData") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_HistoryReadResult, historyData) - offsetof(UA_HistoryReadResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ReadRawModifiedDetails */
static UA_DataTypeMember ReadRawModifiedDetails_members[5] = {
{
    UA_TYPENAME("IsReadModified") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, startTime) - offsetof(UA_ReadRawModifiedDetails, isReadModified) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, endTime) - offsetof(UA_ReadRawModifiedDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NumValuesPerNode") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, numValuesPerNode) - offsetof(UA_ReadRawModifiedDetails, endTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReturnBounds") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, returnBounds) - offsetof(UA_ReadRawModifiedDetails, numValuesPerNode) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ReadAtTimeDetails */
static UA_DataTypeMember ReadAtTimeDetails_members[2] = {
{
    UA_TYPENAME("ReqTimes") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UseSimpleBounds") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReadAtTimeDetails, useSimpleBounds) - offsetof(UA_ReadAtTimeDetails, reqTimes) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ReadAnnotationDataDetails */
static UA_DataTypeMember ReadAnnotationDataDetails_members[1] = {
{
    UA_TYPENAME("ReqTimes") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryData */
static UA_DataTypeMember HistoryData_members[1] = {
{
    UA_TYPENAME("DataValues") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryReadRequest */
static UA_DataTypeMember HistoryReadRequest_members[5] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryReadDetails") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_HistoryReadRequest, historyReadDetails) - offsetof(UA_HistoryReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_HistoryReadRequest, timestampsToReturn) - offsetof(UA_HistoryReadRequest, historyReadDetails) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReleaseContinuationPoints") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_HistoryReadRequest, releaseContinuationPoints) - offsetof(UA_HistoryReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToRead") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYREADVALUEID], /* .memberType */
    offsetof(UA_HistoryReadRequest, nodesToReadSize) - offsetof(UA_HistoryReadRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryReadResponse */
static UA_DataTypeMember HistoryReadResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYREADRESULT], /* .memberType */
    offsetof(UA_HistoryReadResponse, resultsSize) - offsetof(UA_HistoryReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_HistoryReadResponse, diagnosticInfosSize) - offsetof(UA_HistoryReadResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* WriteValue */
static UA_DataTypeMember WriteValue_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_WriteValue, attributeId) - offsetof(UA_WriteValue, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_WriteValue, indexRange) - offsetof(UA_WriteValue, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_WriteValue, value) - offsetof(UA_WriteValue, indexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* WriteRequest */
static UA_DataTypeMember WriteRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToWrite") /* .memberName */
    &UA_TYPES[UA_TYPES_WRITEVALUE], /* .memberType */
    offsetof(UA_WriteRequest, nodesToWriteSize) - offsetof(UA_WriteRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* WriteResponse */
static UA_DataTypeMember WriteResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_WriteResponse, resultsSize) - offsetof(UA_WriteResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_WriteResponse, diagnosticInfosSize) - offsetof(UA_WriteResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryUpdateDetails */
static UA_DataTypeMember HistoryUpdateDetails_members[1] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryUpdateType */
static UA_DataTypeMember HistoryUpdateType_members[4] = {
{
    UA_TYPENAME("Insert") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Replace") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Update") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Delete") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* PerformUpdateType */
static UA_DataTypeMember PerformUpdateType_members[4] = {
{
    UA_TYPENAME("Insert") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Replace") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Update") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Remove") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* UpdateDataDetails */
static UA_DataTypeMember UpdateDataDetails_members[3] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PerformInsertReplace") /* .memberName */
    &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE], /* .memberType */
    offsetof(UA_UpdateDataDetails, performInsertReplace) - offsetof(UA_UpdateDataDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UpdateValues") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_UpdateDataDetails, updateValuesSize) - offsetof(UA_UpdateDataDetails, performInsertReplace) - sizeof(UA_PerformUpdateType), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* UpdateStructureDataDetails */
static UA_DataTypeMember UpdateStructureDataDetails_members[3] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PerformInsertReplace") /* .memberName */
    &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE], /* .memberType */
    offsetof(UA_UpdateStructureDataDetails, performInsertReplace) - offsetof(UA_UpdateStructureDataDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UpdateValues") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_UpdateStructureDataDetails, updateValuesSize) - offsetof(UA_UpdateStructureDataDetails, performInsertReplace) - sizeof(UA_PerformUpdateType), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteRawModifiedDetails */
static UA_DataTypeMember DeleteRawModifiedDetails_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsDeleteModified") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteRawModifiedDetails, isDeleteModified) - offsetof(UA_DeleteRawModifiedDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_DeleteRawModifiedDetails, startTime) - offsetof(UA_DeleteRawModifiedDetails, isDeleteModified) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_DeleteRawModifiedDetails, endTime) - offsetof(UA_DeleteRawModifiedDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteAtTimeDetails */
static UA_DataTypeMember DeleteAtTimeDetails_members[2] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReqTimes") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_DeleteAtTimeDetails, reqTimesSize) - offsetof(UA_DeleteAtTimeDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteEventDetails */
static UA_DataTypeMember DeleteEventDetails_members[2] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventIds") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_DeleteEventDetails, eventIdsSize) - offsetof(UA_DeleteEventDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryUpdateResult */
static UA_DataTypeMember HistoryUpdateResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OperationResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_HistoryUpdateResult, operationResultsSize) - offsetof(UA_HistoryUpdateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_HistoryUpdateResult, diagnosticInfosSize) - offsetof(UA_HistoryUpdateResult, operationResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryUpdateRequest */
static UA_DataTypeMember HistoryUpdateRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryUpdateDetails") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_HistoryUpdateRequest, historyUpdateDetailsSize) - offsetof(UA_HistoryUpdateRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryUpdateResponse */
static UA_DataTypeMember HistoryUpdateResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT], /* .memberType */
    offsetof(UA_HistoryUpdateResponse, resultsSize) - offsetof(UA_HistoryUpdateResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_HistoryUpdateResponse, diagnosticInfosSize) - offsetof(UA_HistoryUpdateResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* CallMethodRequest */
static UA_DataTypeMember CallMethodRequest_members[3] = {
{
    UA_TYPENAME("ObjectId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MethodId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_CallMethodRequest, methodId) - offsetof(UA_CallMethodRequest, objectId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_CallMethodRequest, inputArgumentsSize) - offsetof(UA_CallMethodRequest, methodId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* CallMethodResult */
static UA_DataTypeMember CallMethodResult_members[4] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InputArgumentResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_CallMethodResult, inputArgumentResultsSize) - offsetof(UA_CallMethodResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InputArgumentDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfosSize) - offsetof(UA_CallMethodResult, inputArgumentResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OutputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_CallMethodResult, outputArgumentsSize) - offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfos) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* CallRequest */
static UA_DataTypeMember CallRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MethodsToCall") /* .memberName */
    &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], /* .memberType */
    offsetof(UA_CallRequest, methodsToCallSize) - offsetof(UA_CallRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* CallResponse */
static UA_DataTypeMember CallResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_CALLMETHODRESULT], /* .memberType */
    offsetof(UA_CallResponse, resultsSize) - offsetof(UA_CallResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_CallResponse, diagnosticInfosSize) - offsetof(UA_CallResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* MonitoringMode */
static UA_DataTypeMember MonitoringMode_members[3] = {
{
    UA_TYPENAME("Disabled") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Sampling") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Reporting") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* DataChangeTrigger */
static UA_DataTypeMember DataChangeTrigger_members[3] = {
{
    UA_TYPENAME("Status") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StatusValue") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("StatusValueTimestamp") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* DeadbandType */
static UA_DataTypeMember DeadbandType_members[3] = {
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Absolute") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Percent") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* DataChangeFilter */
static UA_DataTypeMember DataChangeFilter_members[3] = {
{
    UA_TYPENAME("Trigger") /* .memberName */
    &UA_TYPES[UA_TYPES_DATACHANGETRIGGER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeadbandType") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataChangeFilter, deadbandType) - offsetof(UA_DataChangeFilter, trigger) - sizeof(UA_DataChangeTrigger), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeadbandValue") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_DataChangeFilter, deadbandValue) - offsetof(UA_DataChangeFilter, deadbandType) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EventFilter */
static UA_DataTypeMember EventFilter_members[2] = {
{
    UA_TYPENAME("SelectClauses") /* .memberName */
    &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WhereClause") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTER], /* .memberType */
    offsetof(UA_EventFilter, whereClause) - offsetof(UA_EventFilter, selectClauses) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AggregateConfiguration */
static UA_DataTypeMember AggregateConfiguration_members[5] = {
{
    UA_TYPENAME("UseServerCapabilitiesDefaults") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TreatUncertainAsBad") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - offsetof(UA_AggregateConfiguration, useServerCapabilitiesDefaults) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PercentDataBad") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_AggregateConfiguration, percentDataBad) - offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PercentDataGood") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_AggregateConfiguration, percentDataGood) - offsetof(UA_AggregateConfiguration, percentDataBad) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UseSlopedExtrapolation") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_AggregateConfiguration, useSlopedExtrapolation) - offsetof(UA_AggregateConfiguration, percentDataGood) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AggregateFilter */
static UA_DataTypeMember AggregateFilter_members[4] = {
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AggregateFilter, aggregateType) - offsetof(UA_AggregateFilter, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProcessingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_AggregateFilter, processingInterval) - offsetof(UA_AggregateFilter, aggregateType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */
    offsetof(UA_AggregateFilter, aggregateConfiguration) - offsetof(UA_AggregateFilter, processingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EventFilterResult */
static UA_DataTypeMember EventFilterResult_members[3] = {
{
    UA_TYPENAME("SelectClauseResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SelectClauseDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_EventFilterResult, selectClauseDiagnosticInfosSize) - offsetof(UA_EventFilterResult, selectClauseResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WhereClauseResult") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT], /* .memberType */
    offsetof(UA_EventFilterResult, whereClauseResult) - offsetof(UA_EventFilterResult, selectClauseDiagnosticInfos) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AggregateFilterResult */
static UA_DataTypeMember AggregateFilterResult_members[3] = {
{
    UA_TYPENAME("RevisedStartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedProcessingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_AggregateFilterResult, revisedProcessingInterval) - offsetof(UA_AggregateFilterResult, revisedStartTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedAggregateConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */
    offsetof(UA_AggregateFilterResult, revisedAggregateConfiguration) - offsetof(UA_AggregateFilterResult, revisedProcessingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* MonitoringParameters */
static UA_DataTypeMember MonitoringParameters_members[5] = {
{
    UA_TYPENAME("ClientHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_MonitoringParameters, samplingInterval) - offsetof(UA_MonitoringParameters, clientHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Filter") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_MonitoringParameters, filter) - offsetof(UA_MonitoringParameters, samplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueueSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoringParameters, queueSize) - offsetof(UA_MonitoringParameters, filter) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscardOldest") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_MonitoringParameters, discardOldest) - offsetof(UA_MonitoringParameters, queueSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* MonitoredItemCreateRequest */
static UA_DataTypeMember MonitoredItemCreateRequest_members[3] = {
{
    UA_TYPENAME("ItemToMonitor") /* .memberName */
    &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoringMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */
    offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - offsetof(UA_MonitoredItemCreateRequest, itemToMonitor) - sizeof(UA_ReadValueId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedParameters") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */
    offsetof(UA_MonitoredItemCreateRequest, requestedParameters) - offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* MonitoredItemCreateResult */
static UA_DataTypeMember MonitoredItemCreateResult_members[5] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - offsetof(UA_MonitoredItemCreateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedSamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedQueueSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FilterResult") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, filterResult) - offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CreateMonitoredItemsRequest */
static UA_DataTypeMember CreateMonitoredItemsRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - offsetof(UA_CreateMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ItemsToCreate") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], /* .memberType */
    offsetof(UA_CreateMonitoredItemsRequest, itemsToCreateSize) - offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* CreateMonitoredItemsResponse */
static UA_DataTypeMember CreateMonitoredItemsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], /* .memberType */
    offsetof(UA_CreateMonitoredItemsResponse, resultsSize) - offsetof(UA_CreateMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_CreateMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_CreateMonitoredItemsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* MonitoredItemModifyRequest */
static UA_DataTypeMember MonitoredItemModifyRequest_members[2] = {
{
    UA_TYPENAME("MonitoredItemId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedParameters") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */
    offsetof(UA_MonitoredItemModifyRequest, requestedParameters) - offsetof(UA_MonitoredItemModifyRequest, monitoredItemId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* MonitoredItemModifyResult */
static UA_DataTypeMember MonitoredItemModifyResult_members[4] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedSamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemModifyResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedQueueSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FilterResult") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_MonitoredItemModifyResult, filterResult) - offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ModifyMonitoredItemsRequest */
static UA_DataTypeMember ModifyMonitoredItemsRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - offsetof(UA_ModifyMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ItemsToModify") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsRequest, itemsToModifySize) - offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ModifyMonitoredItemsResponse */
static UA_DataTypeMember ModifyMonitoredItemsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsResponse, resultsSize) - offsetof(UA_ModifyMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_ModifyMonitoredItemsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SetMonitoringModeRequest */
static UA_DataTypeMember SetMonitoringModeRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetMonitoringModeRequest, subscriptionId) - offsetof(UA_SetMonitoringModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoringMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */
    offsetof(UA_SetMonitoringModeRequest, monitoringMode) - offsetof(UA_SetMonitoringModeRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetMonitoringModeRequest, monitoredItemIdsSize) - offsetof(UA_SetMonitoringModeRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SetMonitoringModeResponse */
static UA_DataTypeMember SetMonitoringModeResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetMonitoringModeResponse, resultsSize) - offsetof(UA_SetMonitoringModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetMonitoringModeResponse, diagnosticInfosSize) - offsetof(UA_SetMonitoringModeResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SetTriggeringRequest */
static UA_DataTypeMember SetTriggeringRequest_members[5] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, subscriptionId) - offsetof(UA_SetTriggeringRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TriggeringItemId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, triggeringItemId) - offsetof(UA_SetTriggeringRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LinksToAdd") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, linksToAddSize) - offsetof(UA_SetTriggeringRequest, triggeringItemId) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LinksToRemove") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, linksToRemoveSize) - offsetof(UA_SetTriggeringRequest, linksToAdd) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SetTriggeringResponse */
static UA_DataTypeMember SetTriggeringResponse_members[5] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetTriggeringResponse, addResultsSize) - offsetof(UA_SetTriggeringResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetTriggeringResponse, addDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, addResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RemoveResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetTriggeringResponse, removeResultsSize) - offsetof(UA_SetTriggeringResponse, addDiagnosticInfos) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RemoveDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetTriggeringResponse, removeDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, removeResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteMonitoredItemsRequest */
static UA_DataTypeMember DeleteMonitoredItemsRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - offsetof(UA_DeleteMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsRequest, monitoredItemIdsSize) - offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteMonitoredItemsResponse */
static UA_DataTypeMember DeleteMonitoredItemsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsResponse, resultsSize) - offsetof(UA_DeleteMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_DeleteMonitoredItemsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* CreateSubscriptionRequest */
static UA_DataTypeMember CreateSubscriptionRequest_members[7] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - offsetof(UA_CreateSubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingEnabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Priority") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, priority) - offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* CreateSubscriptionResponse */
static UA_DataTypeMember CreateSubscriptionResponse_members[5] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, subscriptionId) - offsetof(UA_CreateSubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - offsetof(UA_CreateSubscriptionResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ModifySubscriptionRequest */
static UA_DataTypeMember ModifySubscriptionRequest_members[7] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, subscriptionId) - offsetof(UA_ModifySubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - offsetof(UA_ModifySubscriptionRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Priority") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, priority) - offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ModifySubscriptionResponse */
static UA_DataTypeMember ModifySubscriptionResponse_members[4] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - offsetof(UA_ModifySubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SetPublishingModeRequest */
static UA_DataTypeMember SetPublishingModeRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingEnabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_SetPublishingModeRequest, publishingEnabled) - offsetof(UA_SetPublishingModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetPublishingModeRequest, subscriptionIdsSize) - offsetof(UA_SetPublishingModeRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SetPublishingModeResponse */
static UA_DataTypeMember SetPublishingModeResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetPublishingModeResponse, resultsSize) - offsetof(UA_SetPublishingModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetPublishingModeResponse, diagnosticInfosSize) - offsetof(UA_SetPublishingModeResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* NotificationMessage */
static UA_DataTypeMember NotificationMessage_members[3] = {
{
    UA_TYPENAME("SequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_NotificationMessage, publishTime) - offsetof(UA_NotificationMessage, sequenceNumber) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationData") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_NotificationMessage, notificationDataSize) - offsetof(UA_NotificationMessage, publishTime) - sizeof(UA_DateTime), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* MonitoredItemNotification */
static UA_DataTypeMember MonitoredItemNotification_members[2] = {
{
    UA_TYPENAME("ClientHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_MonitoredItemNotification, value) - offsetof(UA_MonitoredItemNotification, clientHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EventFieldList */
static UA_DataTypeMember EventFieldList_members[2] = {
{
    UA_TYPENAME("ClientHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventFields") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_EventFieldList, eventFieldsSize) - offsetof(UA_EventFieldList, clientHandle) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryEventFieldList */
static UA_DataTypeMember HistoryEventFieldList_members[1] = {
{
    UA_TYPENAME("EventFields") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* StatusChangeNotification */
static UA_DataTypeMember StatusChangeNotification_members[2] = {
{
    UA_TYPENAME("Status") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfo") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_StatusChangeNotification, diagnosticInfo) - offsetof(UA_StatusChangeNotification, status) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SubscriptionAcknowledgement */
static UA_DataTypeMember SubscriptionAcknowledgement_members[2] = {
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionAcknowledgement, sequenceNumber) - offsetof(UA_SubscriptionAcknowledgement, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PublishRequest */
static UA_DataTypeMember PublishRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionAcknowledgements") /* .memberName */
    &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT], /* .memberType */
    offsetof(UA_PublishRequest, subscriptionAcknowledgementsSize) - offsetof(UA_PublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PublishResponse */
static UA_DataTypeMember PublishResponse_members[7] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PublishResponse, subscriptionId) - offsetof(UA_PublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PublishResponse, availableSequenceNumbersSize) - offsetof(UA_PublishResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MoreNotifications") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_PublishResponse, moreNotifications) - offsetof(UA_PublishResponse, availableSequenceNumbers) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationMessage") /* .memberName */
    &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */
    offsetof(UA_PublishResponse, notificationMessage) - offsetof(UA_PublishResponse, moreNotifications) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_PublishResponse, resultsSize) - offsetof(UA_PublishResponse, notificationMessage) - sizeof(UA_NotificationMessage), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_PublishResponse, diagnosticInfosSize) - offsetof(UA_PublishResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* RepublishRequest */
static UA_DataTypeMember RepublishRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RepublishRequest, subscriptionId) - offsetof(UA_RepublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RetransmitSequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RepublishRequest, retransmitSequenceNumber) - offsetof(UA_RepublishRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* RepublishResponse */
static UA_DataTypeMember RepublishResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationMessage") /* .memberName */
    &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */
    offsetof(UA_RepublishResponse, notificationMessage) - offsetof(UA_RepublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TransferResult */
static UA_DataTypeMember TransferResult_members[2] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TransferResult, availableSequenceNumbersSize) - offsetof(UA_TransferResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* TransferSubscriptionsRequest */
static UA_DataTypeMember TransferSubscriptionsRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TransferSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_TransferSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SendInitialValues") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_TransferSubscriptionsRequest, sendInitialValues) - offsetof(UA_TransferSubscriptionsRequest, subscriptionIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TransferSubscriptionsResponse */
static UA_DataTypeMember TransferSubscriptionsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_TRANSFERRESULT], /* .memberType */
    offsetof(UA_TransferSubscriptionsResponse, resultsSize) - offsetof(UA_TransferSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_TransferSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_TransferSubscriptionsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteSubscriptionsRequest */
static UA_DataTypeMember DeleteSubscriptionsRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DeleteSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_DeleteSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DeleteSubscriptionsResponse */
static UA_DataTypeMember DeleteSubscriptionsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteSubscriptionsResponse, resultsSize) - offsetof(UA_DeleteSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_DeleteSubscriptionsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* BuildInfo */
static UA_DataTypeMember BuildInfo_members[6] = {
{
    UA_TYPENAME("ProductUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ManufacturerName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, manufacturerName) - offsetof(UA_BuildInfo, productUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProductName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, productName) - offsetof(UA_BuildInfo, manufacturerName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SoftwareVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, softwareVersion) - offsetof(UA_BuildInfo, productName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuildNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, buildNumber) - offsetof(UA_BuildInfo, softwareVersion) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuildDate") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_BuildInfo, buildDate) - offsetof(UA_BuildInfo, buildNumber) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* RedundancySupport */
static UA_DataTypeMember RedundancySupport_members[6] = {
{
    UA_TYPENAME("None") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Cold") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Warm") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Hot") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Transparent") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("HotAndMirrored") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ServerState */
static UA_DataTypeMember ServerState_members[8] = {
{
    UA_TYPENAME("Running") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Failed") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("NoConfiguration") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Suspended") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Shutdown") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Test") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("CommunicationFault") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Unknown") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* RedundantServerDataType */
static UA_DataTypeMember RedundantServerDataType_members[3] = {
{
    UA_TYPENAME("ServerId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServiceLevel") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_RedundantServerDataType, serviceLevel) - offsetof(UA_RedundantServerDataType, serverId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerState") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVERSTATE], /* .memberType */
    offsetof(UA_RedundantServerDataType, serverState) - offsetof(UA_RedundantServerDataType, serviceLevel) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EndpointUrlListDataType */
static UA_DataTypeMember EndpointUrlListDataType_members[1] = {
{
    UA_TYPENAME("EndpointUrlList") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* NetworkGroupDataType */
static UA_DataTypeMember NetworkGroupDataType_members[2] = {
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NetworkPaths") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTURLLISTDATATYPE], /* .memberType */
    offsetof(UA_NetworkGroupDataType, networkPathsSize) - offsetof(UA_NetworkGroupDataType, serverUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SamplingIntervalDiagnosticsDataType */
static UA_DataTypeMember SamplingIntervalDiagnosticsDataType_members[4] = {
{
    UA_TYPENAME("SamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SamplingIntervalDiagnosticsDataType, monitoredItemCount) - offsetof(UA_SamplingIntervalDiagnosticsDataType, samplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxMonitoredItemCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SamplingIntervalDiagnosticsDataType, maxMonitoredItemCount) - offsetof(UA_SamplingIntervalDiagnosticsDataType, monitoredItemCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisabledMonitoredItemCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SamplingIntervalDiagnosticsDataType, disabledMonitoredItemCount) - offsetof(UA_SamplingIntervalDiagnosticsDataType, maxMonitoredItemCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ServerDiagnosticsSummaryDataType */
static UA_DataTypeMember ServerDiagnosticsSummaryDataType_members[12] = {
{
    UA_TYPENAME("ServerViewCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, serverViewCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CumulatedSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityRejectedSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RejectedSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionTimeoutCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionAbortCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentSubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CumulatedSubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingIntervalCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityRejectedRequestsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RejectedRequestsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ServerStatusDataType */
static UA_DataTypeMember ServerStatusDataType_members[6] = {
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ServerStatusDataType, currentTime) - offsetof(UA_ServerStatusDataType, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("State") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVERSTATE], /* .memberType */
    offsetof(UA_ServerStatusDataType, state) - offsetof(UA_ServerStatusDataType, currentTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuildInfo") /* .memberName */
    &UA_TYPES[UA_TYPES_BUILDINFO], /* .memberType */
    offsetof(UA_ServerStatusDataType, buildInfo) - offsetof(UA_ServerStatusDataType, state) - sizeof(UA_ServerState), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecondsTillShutdown") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerStatusDataType, secondsTillShutdown) - offsetof(UA_ServerStatusDataType, buildInfo) - sizeof(UA_BuildInfo), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ShutdownReason") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ServerStatusDataType, shutdownReason) - offsetof(UA_ServerStatusDataType, secondsTillShutdown) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SessionSecurityDiagnosticsDataType */
static UA_DataTypeMember SessionSecurityDiagnosticsDataType_members[9] = {
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientUserIdOfSession") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdOfSession) - offsetof(UA_SessionSecurityDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientUserIdHistory") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdHistorySize) - offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdOfSession) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationMechanism") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, authenticationMechanism) - offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdHistory) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Encoding") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, encoding) - offsetof(UA_SessionSecurityDiagnosticsDataType, authenticationMechanism) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportProtocol") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, transportProtocol) - offsetof(UA_SessionSecurityDiagnosticsDataType, encoding) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, securityMode) - offsetof(UA_SessionSecurityDiagnosticsDataType, transportProtocol) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, securityPolicyUri) - offsetof(UA_SessionSecurityDiagnosticsDataType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, clientCertificate) - offsetof(UA_SessionSecurityDiagnosticsDataType, securityPolicyUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ServiceCounterDataType */
static UA_DataTypeMember ServiceCounterDataType_members[2] = {
{
    UA_TYPENAME("TotalCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ErrorCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServiceCounterDataType, errorCount) - offsetof(UA_ServiceCounterDataType, totalCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* StatusResult */
static UA_DataTypeMember StatusResult_members[2] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfo") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_StatusResult, diagnosticInfo) - offsetof(UA_StatusResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SubscriptionDiagnosticsDataType */
static UA_DataTypeMember SubscriptionDiagnosticsDataType_members[31] = {
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, subscriptionId) - offsetof(UA_SubscriptionDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Priority") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, priority) - offsetof(UA_SubscriptionDiagnosticsDataType, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, publishingInterval) - offsetof(UA_SubscriptionDiagnosticsDataType, priority) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, maxKeepAliveCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, maxLifetimeCount) - offsetof(UA_SubscriptionDiagnosticsDataType, maxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, maxNotificationsPerPublish) - offsetof(UA_SubscriptionDiagnosticsDataType, maxLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingEnabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, publishingEnabled) - offsetof(UA_SubscriptionDiagnosticsDataType, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModifyCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, modifyCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishingEnabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EnableCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, enableCount) - offsetof(UA_SubscriptionDiagnosticsDataType, modifyCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisableCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, disableCount) - offsetof(UA_SubscriptionDiagnosticsDataType, enableCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, republishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, disableCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishMessageRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishMessageCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, transferRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferredToAltClientCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, transferredToAltClientCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferredToSameClientCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, transferredToSameClientCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferredToAltClientCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, publishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferredToSameClientCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataChangeNotificationsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, dataChangeNotificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventNotificationsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, eventNotificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, dataChangeNotificationsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, notificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, eventNotificationsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LatePublishRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, latePublishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, notificationsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, currentKeepAliveCount) - offsetof(UA_SubscriptionDiagnosticsDataType, latePublishRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, currentLifetimeCount) - offsetof(UA_SubscriptionDiagnosticsDataType, currentKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnacknowledgedMessageCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, unacknowledgedMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, currentLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscardedMessageCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, discardedMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, unacknowledgedMessageCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, monitoredItemCount) - offsetof(UA_SubscriptionDiagnosticsDataType, discardedMessageCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisabledMonitoredItemCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, disabledMonitoredItemCount) - offsetof(UA_SubscriptionDiagnosticsDataType, monitoredItemCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoringQueueOverflowCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, monitoringQueueOverflowCount) - offsetof(UA_SubscriptionDiagnosticsDataType, disabledMonitoredItemCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NextSequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, nextSequenceNumber) - offsetof(UA_SubscriptionDiagnosticsDataType, monitoringQueueOverflowCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventQueueOverflowCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, eventQueueOverflowCount) - offsetof(UA_SubscriptionDiagnosticsDataType, nextSequenceNumber) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ModelChangeStructureVerbMask */
static UA_DataTypeMember ModelChangeStructureVerbMask_members[5] = {
{
    UA_TYPENAME("NodeAdded") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("NodeDeleted") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ReferenceAdded") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ReferenceDeleted") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("DataTypeChanged") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ModelChangeStructureDataType */
static UA_DataTypeMember ModelChangeStructureDataType_members[3] = {
{
    UA_TYPENAME("Affected") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AffectedType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_ModelChangeStructureDataType, affectedType) - offsetof(UA_ModelChangeStructureDataType, affected) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Verb") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_ModelChangeStructureDataType, verb) - offsetof(UA_ModelChangeStructureDataType, affectedType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SemanticChangeStructureDataType */
static UA_DataTypeMember SemanticChangeStructureDataType_members[2] = {
{
    UA_TYPENAME("Affected") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AffectedType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_SemanticChangeStructureDataType, affectedType) - offsetof(UA_SemanticChangeStructureDataType, affected) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* Range */
static UA_DataTypeMember Range_members[2] = {
{
    UA_TYPENAME("Low") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("High") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_Range, high) - offsetof(UA_Range, low) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EUInformation */
static UA_DataTypeMember EUInformation_members[4] = {
{
    UA_TYPENAME("NamespaceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnitId") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EUInformation, unitId) - offsetof(UA_EUInformation, namespaceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EUInformation, displayName) - offsetof(UA_EUInformation, unitId) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EUInformation, description) - offsetof(UA_EUInformation, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AxisScaleEnumeration */
static UA_DataTypeMember AxisScaleEnumeration_members[3] = {
{
    UA_TYPENAME("Linear") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Log") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Ln") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ComplexNumberType */
static UA_DataTypeMember ComplexNumberType_members[2] = {
{
    UA_TYPENAME("Real") /* .memberName */
    &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Imaginary") /* .memberName */
    &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */
    offsetof(UA_ComplexNumberType, imaginary) - offsetof(UA_ComplexNumberType, real) - sizeof(UA_Float), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DoubleComplexNumberType */
static UA_DataTypeMember DoubleComplexNumberType_members[2] = {
{
    UA_TYPENAME("Real") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Imaginary") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_DoubleComplexNumberType, imaginary) - offsetof(UA_DoubleComplexNumberType, real) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AxisInformation */
static UA_DataTypeMember AxisInformation_members[5] = {
{
    UA_TYPENAME("EngineeringUnits") /* .memberName */
    &UA_TYPES[UA_TYPES_EUINFORMATION], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EURange") /* .memberName */
    &UA_TYPES[UA_TYPES_RANGE], /* .memberType */
    offsetof(UA_AxisInformation, eURange) - offsetof(UA_AxisInformation, engineeringUnits) - sizeof(UA_EUInformation), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Title") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_AxisInformation, title) - offsetof(UA_AxisInformation, eURange) - sizeof(UA_Range), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AxisScaleType") /* .memberName */
    &UA_TYPES[UA_TYPES_AXISSCALEENUMERATION], /* .memberType */
    offsetof(UA_AxisInformation, axisScaleType) - offsetof(UA_AxisInformation, title) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AxisSteps") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_AxisInformation, axisStepsSize) - offsetof(UA_AxisInformation, axisScaleType) - sizeof(UA_AxisScaleEnumeration), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* XVType */
static UA_DataTypeMember XVType_members[2] = {
{
    UA_TYPENAME("X") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */
    offsetof(UA_XVType, value) - offsetof(UA_XVType, x) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ProgramDiagnosticDataType */
static UA_DataTypeMember ProgramDiagnosticDataType_members[10] = {
{
    UA_TYPENAME("CreateSessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreateClientName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, createClientName) - offsetof(UA_ProgramDiagnosticDataType, createSessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InvocationCreationTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, invocationCreationTime) - offsetof(UA_ProgramDiagnosticDataType, createClientName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastTransitionTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, lastTransitionTime) - offsetof(UA_ProgramDiagnosticDataType, invocationCreationTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodCall") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, lastMethodCall) - offsetof(UA_ProgramDiagnosticDataType, lastTransitionTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodSessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, lastMethodSessionId) - offsetof(UA_ProgramDiagnosticDataType, lastMethodCall) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodInputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_ARGUMENT], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, lastMethodInputArgumentsSize) - offsetof(UA_ProgramDiagnosticDataType, lastMethodSessionId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodOutputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_ARGUMENT], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, lastMethodOutputArgumentsSize) - offsetof(UA_ProgramDiagnosticDataType, lastMethodInputArguments) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodCallTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, lastMethodCallTime) - offsetof(UA_ProgramDiagnosticDataType, lastMethodOutputArguments) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodReturnStatus") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSRESULT], /* .memberType */
    offsetof(UA_ProgramDiagnosticDataType, lastMethodReturnStatus) - offsetof(UA_ProgramDiagnosticDataType, lastMethodCallTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ProgramDiagnostic2DataType */
static UA_DataTypeMember ProgramDiagnostic2DataType_members[12] = {
{
    UA_TYPENAME("CreateSessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreateClientName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, createClientName) - offsetof(UA_ProgramDiagnostic2DataType, createSessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InvocationCreationTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, invocationCreationTime) - offsetof(UA_ProgramDiagnostic2DataType, createClientName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastTransitionTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastTransitionTime) - offsetof(UA_ProgramDiagnostic2DataType, invocationCreationTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodCall") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodCall) - offsetof(UA_ProgramDiagnostic2DataType, lastTransitionTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodSessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodSessionId) - offsetof(UA_ProgramDiagnostic2DataType, lastMethodCall) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodInputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_ARGUMENT], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodInputArgumentsSize) - offsetof(UA_ProgramDiagnostic2DataType, lastMethodSessionId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodOutputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_ARGUMENT], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodOutputArgumentsSize) - offsetof(UA_ProgramDiagnostic2DataType, lastMethodInputArguments) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodInputValues") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodInputValuesSize) - offsetof(UA_ProgramDiagnostic2DataType, lastMethodOutputArguments) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodOutputValues") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodOutputValuesSize) - offsetof(UA_ProgramDiagnostic2DataType, lastMethodInputValues) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodCallTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodCallTime) - offsetof(UA_ProgramDiagnostic2DataType, lastMethodOutputValues) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastMethodReturnStatus") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ProgramDiagnostic2DataType, lastMethodReturnStatus) - offsetof(UA_ProgramDiagnostic2DataType, lastMethodCallTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* Annotation */
static UA_DataTypeMember Annotation_members[3] = {
{
    UA_TYPENAME("Message") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_Annotation, userName) - offsetof(UA_Annotation, message) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AnnotationTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_Annotation, annotationTime) - offsetof(UA_Annotation, userName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ExceptionDeviationFormat */
static UA_DataTypeMember ExceptionDeviationFormat_members[5] = {
{
    UA_TYPENAME("AbsoluteValue") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("PercentOfValue") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("PercentOfRange") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("PercentOfEURange") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("Unknown") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* EndpointType */
static UA_DataTypeMember EndpointType_members[4] = {
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_EndpointType, securityMode) - offsetof(UA_EndpointType, endpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EndpointType, securityPolicyUri) - offsetof(UA_EndpointType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EndpointType, transportProfileUri) - offsetof(UA_EndpointType, securityPolicyUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* StructureDescription */
static UA_DataTypeMember StructureDescription_members[3] = {
{
    UA_TYPENAME("DataTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_StructureDescription, name) - offsetof(UA_StructureDescription, dataTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StructureDefinition") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION], /* .memberType */
    offsetof(UA_StructureDescription, structureDefinition) - offsetof(UA_StructureDescription, name) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* FieldMetaData */
static UA_DataTypeMember FieldMetaData_members[10] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_FieldMetaData, description) - offsetof(UA_FieldMetaData, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FieldFlags") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETFIELDFLAGS], /* .memberType */
    offsetof(UA_FieldMetaData, fieldFlags) - offsetof(UA_FieldMetaData, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuiltInType") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_FieldMetaData, builtInType) - offsetof(UA_FieldMetaData, fieldFlags) - sizeof(UA_DataSetFieldFlags), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_FieldMetaData, dataType) - offsetof(UA_FieldMetaData, builtInType) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_FieldMetaData, valueRank) - offsetof(UA_FieldMetaData, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_FieldMetaData, arrayDimensionsSize) - offsetof(UA_FieldMetaData, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxStringLength") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_FieldMetaData, maxStringLength) - offsetof(UA_FieldMetaData, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetFieldId") /* .memberName */
    &UA_TYPES[UA_TYPES_GUID], /* .memberType */
    offsetof(UA_FieldMetaData, dataSetFieldId) - offsetof(UA_FieldMetaData, maxStringLength) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Properties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_FieldMetaData, propertiesSize) - offsetof(UA_FieldMetaData, dataSetFieldId) - sizeof(UA_Guid), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PublishedEventsDataType */
static UA_DataTypeMember PublishedEventsDataType_members[3] = {
{
    UA_TYPENAME("EventNotifier") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SelectedFields") /* .memberName */
    &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND], /* .memberType */
    offsetof(UA_PublishedEventsDataType, selectedFieldsSize) - offsetof(UA_PublishedEventsDataType, eventNotifier) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Filter") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTER], /* .memberType */
    offsetof(UA_PublishedEventsDataType, filter) - offsetof(UA_PublishedEventsDataType, selectedFields) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubGroupDataType */
static UA_DataTypeMember PubSubGroupDataType_members[7] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_PubSubGroupDataType, enabled) - offsetof(UA_PubSubGroupDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_PubSubGroupDataType, securityMode) - offsetof(UA_PubSubGroupDataType, enabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroupId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PubSubGroupDataType, securityGroupId) - offsetof(UA_PubSubGroupDataType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityKeyServices") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_PubSubGroupDataType, securityKeyServicesSize) - offsetof(UA_PubSubGroupDataType, securityGroupId) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNetworkMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PubSubGroupDataType, maxNetworkMessageSize) - offsetof(UA_PubSubGroupDataType, securityKeyServices) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GroupProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_PubSubGroupDataType, groupPropertiesSize) - offsetof(UA_PubSubGroupDataType, maxNetworkMessageSize) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* WriterGroupDataType */
static UA_DataTypeMember WriterGroupDataType_members[16] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_WriterGroupDataType, enabled) - offsetof(UA_WriterGroupDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_WriterGroupDataType, securityMode) - offsetof(UA_WriterGroupDataType, enabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroupId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_WriterGroupDataType, securityGroupId) - offsetof(UA_WriterGroupDataType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityKeyServices") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_WriterGroupDataType, securityKeyServicesSize) - offsetof(UA_WriterGroupDataType, securityGroupId) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNetworkMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_WriterGroupDataType, maxNetworkMessageSize) - offsetof(UA_WriterGroupDataType, securityKeyServices) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GroupProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_WriterGroupDataType, groupPropertiesSize) - offsetof(UA_WriterGroupDataType, maxNetworkMessageSize) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriterGroupId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_WriterGroupDataType, writerGroupId) - offsetof(UA_WriterGroupDataType, groupProperties) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_WriterGroupDataType, publishingInterval) - offsetof(UA_WriterGroupDataType, writerGroupId) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("KeepAliveTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_WriterGroupDataType, keepAliveTime) - offsetof(UA_WriterGroupDataType, publishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Priority") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_WriterGroupDataType, priority) - offsetof(UA_WriterGroupDataType, keepAliveTime) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_WriterGroupDataType, localeIdsSize) - offsetof(UA_WriterGroupDataType, priority) - sizeof(UA_Byte), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HeaderLayoutUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_WriterGroupDataType, headerLayoutUri) - offsetof(UA_WriterGroupDataType, localeIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_WriterGroupDataType, transportSettings) - offsetof(UA_WriterGroupDataType, headerLayoutUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_WriterGroupDataType, messageSettings) - offsetof(UA_WriterGroupDataType, transportSettings) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetWriters") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETWRITERDATATYPE], /* .memberType */
    offsetof(UA_WriterGroupDataType, dataSetWritersSize) - offsetof(UA_WriterGroupDataType, messageSettings) - sizeof(UA_ExtensionObject), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* FieldTargetDataType */
static UA_DataTypeMember FieldTargetDataType_members[7] = {
{
    UA_TYPENAME("DataSetFieldId") /* .memberName */
    &UA_TYPES[UA_TYPES_GUID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiverIndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FieldTargetDataType, receiverIndexRange) - offsetof(UA_FieldTargetDataType, dataSetFieldId) - sizeof(UA_Guid), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_FieldTargetDataType, targetNodeId) - offsetof(UA_FieldTargetDataType, receiverIndexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_FieldTargetDataType, attributeId) - offsetof(UA_FieldTargetDataType, targetNodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteIndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FieldTargetDataType, writeIndexRange) - offsetof(UA_FieldTargetDataType, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OverrideValueHandling") /* .memberName */
    &UA_TYPES[UA_TYPES_OVERRIDEVALUEHANDLING], /* .memberType */
    offsetof(UA_FieldTargetDataType, overrideValueHandling) - offsetof(UA_FieldTargetDataType, writeIndexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OverrideValue") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_FieldTargetDataType, overrideValue) - offsetof(UA_FieldTargetDataType, overrideValueHandling) - sizeof(UA_OverrideValueHandling), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SubscribedDataSetMirrorDataType */
static UA_DataTypeMember SubscribedDataSetMirrorDataType_members[2] = {
{
    UA_TYPENAME("ParentNodeName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RolePermissions") /* .memberName */
    &UA_TYPES[UA_TYPES_ROLEPERMISSIONTYPE], /* .memberType */
    offsetof(UA_SubscribedDataSetMirrorDataType, rolePermissionsSize) - offsetof(UA_SubscribedDataSetMirrorDataType, parentNodeName) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SecurityGroupDataType */
static UA_DataTypeMember SecurityGroupDataType_members[9] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroupFolder") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SecurityGroupDataType, securityGroupFolderSize) - offsetof(UA_SecurityGroupDataType, name) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("KeyLifetime") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_SecurityGroupDataType, keyLifetime) - offsetof(UA_SecurityGroupDataType, securityGroupFolder) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SecurityGroupDataType, securityPolicyUri) - offsetof(UA_SecurityGroupDataType, keyLifetime) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxFutureKeyCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SecurityGroupDataType, maxFutureKeyCount) - offsetof(UA_SecurityGroupDataType, securityPolicyUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxPastKeyCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SecurityGroupDataType, maxPastKeyCount) - offsetof(UA_SecurityGroupDataType, maxFutureKeyCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroupId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SecurityGroupDataType, securityGroupId) - offsetof(UA_SecurityGroupDataType, maxPastKeyCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RolePermissions") /* .memberName */
    &UA_TYPES[UA_TYPES_ROLEPERMISSIONTYPE], /* .memberType */
    offsetof(UA_SecurityGroupDataType, rolePermissionsSize) - offsetof(UA_SecurityGroupDataType, securityGroupId) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GroupProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_SecurityGroupDataType, groupPropertiesSize) - offsetof(UA_SecurityGroupDataType, rolePermissions) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubKeyPushTargetDataType */
static UA_DataTypeMember PubSubKeyPushTargetDataType_members[9] = {
{
    UA_TYPENAME("ApplicationUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PushTargetFolder") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, pushTargetFolderSize) - offsetof(UA_PubSubKeyPushTargetDataType, applicationUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, endpointUrl) - offsetof(UA_PubSubKeyPushTargetDataType, pushTargetFolder) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, securityPolicyUri) - offsetof(UA_PubSubKeyPushTargetDataType, endpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserTokenType") /* .memberName */
    &UA_TYPES[UA_TYPES_USERTOKENPOLICY], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, userTokenType) - offsetof(UA_PubSubKeyPushTargetDataType, securityPolicyUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedKeyCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, requestedKeyCount) - offsetof(UA_PubSubKeyPushTargetDataType, userTokenType) - sizeof(UA_UserTokenPolicy), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RetryInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, retryInterval) - offsetof(UA_PubSubKeyPushTargetDataType, requestedKeyCount) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PushTargetProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, pushTargetPropertiesSize) - offsetof(UA_PubSubKeyPushTargetDataType, retryInterval) - sizeof(UA_Double), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroups") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PubSubKeyPushTargetDataType, securityGroupsSize) - offsetof(UA_PubSubKeyPushTargetDataType, pushTargetProperties) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* EnumDefinition */
static UA_DataTypeMember EnumDefinition_members[1] = {
{
    UA_TYPENAME("Fields") /* .memberName */
    &UA_TYPES[UA_TYPES_ENUMFIELD], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ReadEventDetails */
static UA_DataTypeMember ReadEventDetails_members[4] = {
{
    UA_TYPENAME("NumValuesPerNode") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadEventDetails, startTime) - offsetof(UA_ReadEventDetails, numValuesPerNode) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadEventDetails, endTime) - offsetof(UA_ReadEventDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Filter") /* .memberName */
    &UA_TYPES[UA_TYPES_EVENTFILTER], /* .memberType */
    offsetof(UA_ReadEventDetails, filter) - offsetof(UA_ReadEventDetails, endTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ReadProcessedDetails */
static UA_DataTypeMember ReadProcessedDetails_members[5] = {
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadProcessedDetails, endTime) - offsetof(UA_ReadProcessedDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProcessingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ReadProcessedDetails, processingInterval) - offsetof(UA_ReadProcessedDetails, endTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_ReadProcessedDetails, aggregateTypeSize) - offsetof(UA_ReadProcessedDetails, processingInterval) - sizeof(UA_Double), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */
    offsetof(UA_ReadProcessedDetails, aggregateConfiguration) - offsetof(UA_ReadProcessedDetails, aggregateType) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* ModificationInfo */
static UA_DataTypeMember ModificationInfo_members[3] = {
{
    UA_TYPENAME("ModificationTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UpdateType") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYUPDATETYPE], /* .memberType */
    offsetof(UA_ModificationInfo, updateType) - offsetof(UA_ModificationInfo, modificationTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ModificationInfo, userName) - offsetof(UA_ModificationInfo, updateType) - sizeof(UA_HistoryUpdateType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryModifiedData */
static UA_DataTypeMember HistoryModifiedData_members[2] = {
{
    UA_TYPENAME("DataValues") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModificationInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_MODIFICATIONINFO], /* .memberType */
    offsetof(UA_HistoryModifiedData, modificationInfosSize) - offsetof(UA_HistoryModifiedData, dataValues) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* HistoryEvent */
static UA_DataTypeMember HistoryEvent_members[1] = {
{
    UA_TYPENAME("Events") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYEVENTFIELDLIST], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* UpdateEventDetails */
static UA_DataTypeMember UpdateEventDetails_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PerformInsertReplace") /* .memberName */
    &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE], /* .memberType */
    offsetof(UA_UpdateEventDetails, performInsertReplace) - offsetof(UA_UpdateEventDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Filter") /* .memberName */
    &UA_TYPES[UA_TYPES_EVENTFILTER], /* .memberType */
    offsetof(UA_UpdateEventDetails, filter) - offsetof(UA_UpdateEventDetails, performInsertReplace) - sizeof(UA_PerformUpdateType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventData") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYEVENTFIELDLIST], /* .memberType */
    offsetof(UA_UpdateEventDetails, eventDataSize) - offsetof(UA_UpdateEventDetails, filter) - sizeof(UA_EventFilter), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* DataChangeNotification */
static UA_DataTypeMember DataChangeNotification_members[2] = {
{
    UA_TYPENAME("MonitoredItems") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DataChangeNotification, diagnosticInfosSize) - offsetof(UA_DataChangeNotification, monitoredItems) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* EventNotificationList */
static UA_DataTypeMember EventNotificationList_members[1] = {
{
    UA_TYPENAME("Events") /* .memberName */
    &UA_TYPES[UA_TYPES_EVENTFIELDLIST], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* SessionDiagnosticsDataType */
static UA_DataTypeMember SessionDiagnosticsDataType_members[43] = {
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, sessionName) - offsetof(UA_SessionDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientDescription") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, clientDescription) - offsetof(UA_SessionDiagnosticsDataType, sessionName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, serverUri) - offsetof(UA_SessionDiagnosticsDataType, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, endpointUrl) - offsetof(UA_SessionDiagnosticsDataType, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, localeIdsSize) - offsetof(UA_SessionDiagnosticsDataType, endpointUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ActualSessionTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, actualSessionTimeout) - offsetof(UA_SessionDiagnosticsDataType, localeIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxResponseMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, maxResponseMessageSize) - offsetof(UA_SessionDiagnosticsDataType, actualSessionTimeout) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientConnectionTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, clientConnectionTime) - offsetof(UA_SessionDiagnosticsDataType, maxResponseMessageSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientLastContactTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, clientLastContactTime) - offsetof(UA_SessionDiagnosticsDataType, clientConnectionTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentSubscriptionsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, currentSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, clientLastContactTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, currentMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, currentSubscriptionsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentPublishRequestsInQueue") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, currentPublishRequestsInQueue) - offsetof(UA_SessionDiagnosticsDataType, currentMonitoredItemsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TotalRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, totalRequestCount) - offsetof(UA_SessionDiagnosticsDataType, currentPublishRequestsInQueue) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnauthorizedRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, unauthorizedRequestCount) - offsetof(UA_SessionDiagnosticsDataType, totalRequestCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReadCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, readCount) - offsetof(UA_SessionDiagnosticsDataType, unauthorizedRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryReadCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, historyReadCount) - offsetof(UA_SessionDiagnosticsDataType, readCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, writeCount) - offsetof(UA_SessionDiagnosticsDataType, historyReadCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryUpdateCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, historyUpdateCount) - offsetof(UA_SessionDiagnosticsDataType, writeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CallCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, callCount) - offsetof(UA_SessionDiagnosticsDataType, historyUpdateCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreateMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, createMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, callCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModifyMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, modifyMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, createMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SetMonitoringModeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, setMonitoringModeCount) - offsetof(UA_SessionDiagnosticsDataType, modifyMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SetTriggeringCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, setTriggeringCount) - offsetof(UA_SessionDiagnosticsDataType, setMonitoringModeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, setTriggeringCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreateSubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, createSubscriptionCount) - offsetof(UA_SessionDiagnosticsDataType, deleteMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModifySubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, modifySubscriptionCount) - offsetof(UA_SessionDiagnosticsDataType, createSubscriptionCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SetPublishingModeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, setPublishingModeCount) - offsetof(UA_SessionDiagnosticsDataType, modifySubscriptionCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, publishCount) - offsetof(UA_SessionDiagnosticsDataType, setPublishingModeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, republishCount) - offsetof(UA_SessionDiagnosticsDataType, publishCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferSubscriptionsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, transferSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, republishCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteSubscriptionsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, transferSubscriptionsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, addNodesCount) - offsetof(UA_SessionDiagnosticsDataType, deleteSubscriptionsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddReferencesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, addReferencesCount) - offsetof(UA_SessionDiagnosticsDataType, addNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteNodesCount) - offsetof(UA_SessionDiagnosticsDataType, addReferencesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteReferencesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteReferencesCount) - offsetof(UA_SessionDiagnosticsDataType, deleteNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, browseCount) - offsetof(UA_SessionDiagnosticsDataType, deleteReferencesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseNextCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, browseNextCount) - offsetof(UA_SessionDiagnosticsDataType, browseCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TranslateBrowsePathsToNodeIdsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, translateBrowsePathsToNodeIdsCount) - offsetof(UA_SessionDiagnosticsDataType, browseNextCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueryFirstCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, queryFirstCount) - offsetof(UA_SessionDiagnosticsDataType, translateBrowsePathsToNodeIdsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueryNextCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, queryNextCount) - offsetof(UA_SessionDiagnosticsDataType, queryFirstCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RegisterNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, registerNodesCount) - offsetof(UA_SessionDiagnosticsDataType, queryNextCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnregisterNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, unregisterNodesCount) - offsetof(UA_SessionDiagnosticsDataType, registerNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* EnumDescription */
static UA_DataTypeMember EnumDescription_members[4] = {
{
    UA_TYPENAME("DataTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_EnumDescription, name) - offsetof(UA_EnumDescription, dataTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EnumDefinition") /* .memberName */
    &UA_TYPES[UA_TYPES_ENUMDEFINITION], /* .memberType */
    offsetof(UA_EnumDescription, enumDefinition) - offsetof(UA_EnumDescription, name) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuiltInType") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_EnumDescription, builtInType) - offsetof(UA_EnumDescription, enumDefinition) - sizeof(UA_EnumDefinition), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* UABinaryFileDataType */
static UA_DataTypeMember UABinaryFileDataType_members[7] = {
{
    UA_TYPENAME("Namespaces") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StructureDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTUREDESCRIPTION], /* .memberType */
    offsetof(UA_UABinaryFileDataType, structureDataTypesSize) - offsetof(UA_UABinaryFileDataType, namespaces) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EnumDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_ENUMDESCRIPTION], /* .memberType */
    offsetof(UA_UABinaryFileDataType, enumDataTypesSize) - offsetof(UA_UABinaryFileDataType, structureDataTypes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SimpleDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_SIMPLETYPEDESCRIPTION], /* .memberType */
    offsetof(UA_UABinaryFileDataType, simpleDataTypesSize) - offsetof(UA_UABinaryFileDataType, enumDataTypes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SchemaLocation") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UABinaryFileDataType, schemaLocation) - offsetof(UA_UABinaryFileDataType, simpleDataTypes) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FileHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_UABinaryFileDataType, fileHeaderSize) - offsetof(UA_UABinaryFileDataType, schemaLocation) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Body") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_UABinaryFileDataType, body) - offsetof(UA_UABinaryFileDataType, fileHeader) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DataSetMetaDataType */
static UA_DataTypeMember DataSetMetaDataType_members[9] = {
{
    UA_TYPENAME("Namespaces") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StructureDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTUREDESCRIPTION], /* .memberType */
    offsetof(UA_DataSetMetaDataType, structureDataTypesSize) - offsetof(UA_DataSetMetaDataType, namespaces) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EnumDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_ENUMDESCRIPTION], /* .memberType */
    offsetof(UA_DataSetMetaDataType, enumDataTypesSize) - offsetof(UA_DataSetMetaDataType, structureDataTypes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SimpleDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_SIMPLETYPEDESCRIPTION], /* .memberType */
    offsetof(UA_DataSetMetaDataType, simpleDataTypesSize) - offsetof(UA_DataSetMetaDataType, enumDataTypes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DataSetMetaDataType, name) - offsetof(UA_DataSetMetaDataType, simpleDataTypes) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_DataSetMetaDataType, description) - offsetof(UA_DataSetMetaDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Fields") /* .memberName */
    &UA_TYPES[UA_TYPES_FIELDMETADATA], /* .memberType */
    offsetof(UA_DataSetMetaDataType, fieldsSize) - offsetof(UA_DataSetMetaDataType, description) - sizeof(UA_LocalizedText), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetClassId") /* .memberName */
    &UA_TYPES[UA_TYPES_GUID], /* .memberType */
    offsetof(UA_DataSetMetaDataType, dataSetClassId) - offsetof(UA_DataSetMetaDataType, fields) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConfigurationVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE], /* .memberType */
    offsetof(UA_DataSetMetaDataType, configurationVersion) - offsetof(UA_DataSetMetaDataType, dataSetClassId) - sizeof(UA_Guid), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PublishedDataSetDataType */
static UA_DataTypeMember PublishedDataSetDataType_members[5] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetFolder") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PublishedDataSetDataType, dataSetFolderSize) - offsetof(UA_PublishedDataSetDataType, name) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetMetaData") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETMETADATATYPE], /* .memberType */
    offsetof(UA_PublishedDataSetDataType, dataSetMetaData) - offsetof(UA_PublishedDataSetDataType, dataSetFolder) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ExtensionFields") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_PublishedDataSetDataType, extensionFieldsSize) - offsetof(UA_PublishedDataSetDataType, dataSetMetaData) - sizeof(UA_DataSetMetaDataType), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetSource") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_PublishedDataSetDataType, dataSetSource) - offsetof(UA_PublishedDataSetDataType, extensionFields) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DataSetReaderDataType */
static UA_DataTypeMember DataSetReaderDataType_members[17] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DataSetReaderDataType, enabled) - offsetof(UA_DataSetReaderDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublisherId") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_DataSetReaderDataType, publisherId) - offsetof(UA_DataSetReaderDataType, enabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriterGroupId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_DataSetReaderDataType, writerGroupId) - offsetof(UA_DataSetReaderDataType, publisherId) - sizeof(UA_Variant), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetWriterId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT16], /* .memberType */
    offsetof(UA_DataSetReaderDataType, dataSetWriterId) - offsetof(UA_DataSetReaderDataType, writerGroupId) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetMetaData") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETMETADATATYPE], /* .memberType */
    offsetof(UA_DataSetReaderDataType, dataSetMetaData) - offsetof(UA_DataSetReaderDataType, dataSetWriterId) - sizeof(UA_UInt16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetFieldContentMask") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETFIELDCONTENTMASK], /* .memberType */
    offsetof(UA_DataSetReaderDataType, dataSetFieldContentMask) - offsetof(UA_DataSetReaderDataType, dataSetMetaData) - sizeof(UA_DataSetMetaDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageReceiveTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_DataSetReaderDataType, messageReceiveTimeout) - offsetof(UA_DataSetReaderDataType, dataSetFieldContentMask) - sizeof(UA_DataSetFieldContentMask), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("KeyFrameCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataSetReaderDataType, keyFrameCount) - offsetof(UA_DataSetReaderDataType, messageReceiveTimeout) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HeaderLayoutUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DataSetReaderDataType, headerLayoutUri) - offsetof(UA_DataSetReaderDataType, keyFrameCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_DataSetReaderDataType, securityMode) - offsetof(UA_DataSetReaderDataType, headerLayoutUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroupId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_DataSetReaderDataType, securityGroupId) - offsetof(UA_DataSetReaderDataType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityKeyServices") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_DataSetReaderDataType, securityKeyServicesSize) - offsetof(UA_DataSetReaderDataType, securityGroupId) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetReaderProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_DataSetReaderDataType, dataSetReaderPropertiesSize) - offsetof(UA_DataSetReaderDataType, securityKeyServices) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DataSetReaderDataType, transportSettings) - offsetof(UA_DataSetReaderDataType, dataSetReaderProperties) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DataSetReaderDataType, messageSettings) - offsetof(UA_DataSetReaderDataType, transportSettings) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscribedDataSet") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_DataSetReaderDataType, subscribedDataSet) - offsetof(UA_DataSetReaderDataType, messageSettings) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TargetVariablesDataType */
static UA_DataTypeMember TargetVariablesDataType_members[1] = {
{
    UA_TYPENAME("TargetVariables") /* .memberName */
    &UA_TYPES[UA_TYPES_FIELDTARGETDATATYPE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* StandaloneSubscribedDataSetDataType */
static UA_DataTypeMember StandaloneSubscribedDataSetDataType_members[4] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetFolder") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_StandaloneSubscribedDataSetDataType, dataSetFolderSize) - offsetof(UA_StandaloneSubscribedDataSetDataType, name) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetMetaData") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETMETADATATYPE], /* .memberType */
    offsetof(UA_StandaloneSubscribedDataSetDataType, dataSetMetaData) - offsetof(UA_StandaloneSubscribedDataSetDataType, dataSetFolder) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscribedDataSet") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_StandaloneSubscribedDataSetDataType, subscribedDataSet) - offsetof(UA_StandaloneSubscribedDataSetDataType, dataSetMetaData) - sizeof(UA_DataSetMetaDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* DataTypeSchemaHeader */
static UA_DataTypeMember DataTypeSchemaHeader_members[4] = {
{
    UA_TYPENAME("Namespaces") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StructureDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTUREDESCRIPTION], /* .memberType */
    offsetof(UA_DataTypeSchemaHeader, structureDataTypesSize) - offsetof(UA_DataTypeSchemaHeader, namespaces) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EnumDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_ENUMDESCRIPTION], /* .memberType */
    offsetof(UA_DataTypeSchemaHeader, enumDataTypesSize) - offsetof(UA_DataTypeSchemaHeader, structureDataTypes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SimpleDataTypes") /* .memberName */
    &UA_TYPES[UA_TYPES_SIMPLETYPEDESCRIPTION], /* .memberType */
    offsetof(UA_DataTypeSchemaHeader, simpleDataTypesSize) - offsetof(UA_DataTypeSchemaHeader, enumDataTypes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* ReaderGroupDataType */
static UA_DataTypeMember ReaderGroupDataType_members[10] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReaderGroupDataType, enabled) - offsetof(UA_ReaderGroupDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_ReaderGroupDataType, securityMode) - offsetof(UA_ReaderGroupDataType, enabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroupId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ReaderGroupDataType, securityGroupId) - offsetof(UA_ReaderGroupDataType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityKeyServices") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_ReaderGroupDataType, securityKeyServicesSize) - offsetof(UA_ReaderGroupDataType, securityGroupId) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNetworkMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReaderGroupDataType, maxNetworkMessageSize) - offsetof(UA_ReaderGroupDataType, securityKeyServices) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GroupProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_ReaderGroupDataType, groupPropertiesSize) - offsetof(UA_ReaderGroupDataType, maxNetworkMessageSize) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ReaderGroupDataType, transportSettings) - offsetof(UA_ReaderGroupDataType, groupProperties) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ReaderGroupDataType, messageSettings) - offsetof(UA_ReaderGroupDataType, transportSettings) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetReaders") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETREADERDATATYPE], /* .memberType */
    offsetof(UA_ReaderGroupDataType, dataSetReadersSize) - offsetof(UA_ReaderGroupDataType, messageSettings) - sizeof(UA_ExtensionObject), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubConnectionDataType */
static UA_DataTypeMember PubSubConnectionDataType_members[9] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, enabled) - offsetof(UA_PubSubConnectionDataType, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublisherId") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, publisherId) - offsetof(UA_PubSubConnectionDataType, enabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, transportProfileUri) - offsetof(UA_PubSubConnectionDataType, publisherId) - sizeof(UA_Variant), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Address") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, address) - offsetof(UA_PubSubConnectionDataType, transportProfileUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConnectionProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, connectionPropertiesSize) - offsetof(UA_PubSubConnectionDataType, address) - sizeof(UA_ExtensionObject), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportSettings") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, transportSettings) - offsetof(UA_PubSubConnectionDataType, connectionProperties) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriterGroups") /* .memberName */
    &UA_TYPES[UA_TYPES_WRITERGROUPDATATYPE], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, writerGroupsSize) - offsetof(UA_PubSubConnectionDataType, transportSettings) - sizeof(UA_ExtensionObject), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReaderGroups") /* .memberName */
    &UA_TYPES[UA_TYPES_READERGROUPDATATYPE], /* .memberType */
    offsetof(UA_PubSubConnectionDataType, readerGroupsSize) - offsetof(UA_PubSubConnectionDataType, writerGroups) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubConfigurationDataType */
static UA_DataTypeMember PubSubConfigurationDataType_members[3] = {
{
    UA_TYPENAME("PublishedDataSets") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBLISHEDDATASETDATATYPE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Connections") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBSUBCONNECTIONDATATYPE], /* .memberType */
    offsetof(UA_PubSubConfigurationDataType, connectionsSize) - offsetof(UA_PubSubConfigurationDataType, publishedDataSets) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_PubSubConfigurationDataType, enabled) - offsetof(UA_PubSubConfigurationDataType, connections) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* PubSubConfiguration2DataType */
static UA_DataTypeMember PubSubConfiguration2DataType_members[10] = {
{
    UA_TYPENAME("PublishedDataSets") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBLISHEDDATASETDATATYPE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Connections") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBSUBCONNECTIONDATATYPE], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, connectionsSize) - offsetof(UA_PubSubConfiguration2DataType, publishedDataSets) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Enabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, enabled) - offsetof(UA_PubSubConfiguration2DataType, connections) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscribedDataSets") /* .memberName */
    &UA_TYPES[UA_TYPES_STANDALONESUBSCRIBEDDATASETDATATYPE], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, subscribedDataSetsSize) - offsetof(UA_PubSubConfiguration2DataType, enabled) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataSetClasses") /* .memberName */
    &UA_TYPES[UA_TYPES_DATASETMETADATATYPE], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, dataSetClassesSize) - offsetof(UA_PubSubConfiguration2DataType, subscribedDataSets) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DefaultSecurityKeyServices") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, defaultSecurityKeyServicesSize) - offsetof(UA_PubSubConfiguration2DataType, dataSetClasses) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityGroups") /* .memberName */
    &UA_TYPES[UA_TYPES_SECURITYGROUPDATATYPE], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, securityGroupsSize) - offsetof(UA_PubSubConfiguration2DataType, defaultSecurityKeyServices) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PubSubKeyPushTargets") /* .memberName */
    &UA_TYPES[UA_TYPES_PUBSUBKEYPUSHTARGETDATATYPE], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, pubSubKeyPushTargetsSize) - offsetof(UA_PubSubConfiguration2DataType, securityGroups) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConfigurationVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, configurationVersion) - offsetof(UA_PubSubConfiguration2DataType, pubSubKeyPushTargets) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConfigurationProperties") /* .memberName */
    &UA_TYPES[UA_TYPES_KEYVALUEPAIR], /* .memberType */
    offsetof(UA_PubSubConfiguration2DataType, configurationPropertiesSize) - offsetof(UA_PubSubConfiguration2DataType, configurationVersion) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
}};
UA_DataType UA_TYPES[UA_TYPES_COUNT] = {
/* Boolean */
{
    UA_TYPENAME("Boolean") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {1LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Boolean), /* .memSize */
    UA_DATATYPEKIND_BOOLEAN, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Boolean_members  /* .members */
},
/* SByte */
{
    UA_TYPENAME("SByte") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {2LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_SByte), /* .memSize */
    UA_DATATYPEKIND_SBYTE, /* .typeKind */
    true, /* .pointerFree */
    true, /* .overlayable */
    0, /* .membersSize */
    SByte_members  /* .members */
},
/* Byte */
{
    UA_TYPENAME("Byte") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {3LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Byte), /* .memSize */
    UA_DATATYPEKIND_BYTE, /* .typeKind */
    true, /* .pointerFree */
    true, /* .overlayable */
    0, /* .membersSize */
    Byte_members  /* .members */
},
/* Int16 */
{
    UA_TYPENAME("Int16") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {4LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Int16), /* .memSize */
    UA_DATATYPEKIND_INT16, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    Int16_members  /* .members */
},
/* UInt16 */
{
    UA_TYPENAME("UInt16") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {5LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UInt16), /* .memSize */
    UA_DATATYPEKIND_UINT16, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UInt16_members  /* .members */
},
/* Int32 */
{
    UA_TYPENAME("Int32") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {6LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Int32), /* .memSize */
    UA_DATATYPEKIND_INT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    Int32_members  /* .members */
},
/* UInt32 */
{
    UA_TYPENAME("UInt32") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {7LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UInt32), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UInt32_members  /* .members */
},
/* Int64 */
{
    UA_TYPENAME("Int64") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {8LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Int64), /* .memSize */
    UA_DATATYPEKIND_INT64, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    Int64_members  /* .members */
},
/* UInt64 */
{
    UA_TYPENAME("UInt64") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {9LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UInt64), /* .memSize */
    UA_DATATYPEKIND_UINT64, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UInt64_members  /* .members */
},
/* Float */
{
    UA_TYPENAME("Float") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {10LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Float), /* .memSize */
    UA_DATATYPEKIND_FLOAT, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */
    0, /* .membersSize */
    Float_members  /* .members */
},
/* Double */
{
    UA_TYPENAME("Double") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Double), /* .memSize */
    UA_DATATYPEKIND_DOUBLE, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */
    0, /* .membersSize */
    Double_members  /* .members */
},
/* String */
{
    UA_TYPENAME("String") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_String), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    String_members  /* .members */
},
/* DateTime */
{
    UA_TYPENAME("DateTime") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {13LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DateTime), /* .memSize */
    UA_DATATYPEKIND_DATETIME, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    DateTime_members  /* .members */
},
/* Guid */
{
    UA_TYPENAME("Guid") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Guid), /* .memSize */
    UA_DATATYPEKIND_GUID, /* .typeKind */
    true, /* .pointerFree */
    (UA_BINARY_OVERLAYABLE_INTEGER && offsetof(UA_Guid, data2) == sizeof(UA_UInt32) && offsetof(UA_Guid, data3) == (sizeof(UA_UInt16) + sizeof(UA_UInt32)) && offsetof(UA_Guid, data4) == (2*sizeof(UA_UInt32))), /* .overlayable */
    0, /* .membersSize */
    Guid_members  /* .members */
},
/* ByteString */
{
    UA_TYPENAME("ByteString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ByteString), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ByteString_members  /* .members */
},
/* XmlElement */
{
    UA_TYPENAME("XmlElement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {16LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_XmlElement), /* .memSize */
    UA_DATATYPEKIND_XMLELEMENT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    XmlElement_members  /* .members */
},
/* NodeId */
{
    UA_TYPENAME("NodeId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_NodeId), /* .memSize */
    UA_DATATYPEKIND_NODEID, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    NodeId_members  /* .members */
},
/* ExpandedNodeId */
{
    UA_TYPENAME("ExpandedNodeId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {18LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ExpandedNodeId), /* .memSize */
    UA_DATATYPEKIND_EXPANDEDNODEID, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ExpandedNodeId_members  /* .members */
},
/* StatusCode */
{
    UA_TYPENAME("StatusCode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {19LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_StatusCode), /* .memSize */
    UA_DATATYPEKIND_STATUSCODE, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    StatusCode_members  /* .members */
},
/* QualifiedName */
{
    UA_TYPENAME("QualifiedName") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {20LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_QualifiedName), /* .memSize */
    UA_DATATYPEKIND_QUALIFIEDNAME, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    QualifiedName_members  /* .members */
},
/* LocalizedText */
{
    UA_TYPENAME("LocalizedText") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {21LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_LocalizedText), /* .memSize */
    UA_DATATYPEKIND_LOCALIZEDTEXT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    LocalizedText_members  /* .members */
},
/* ExtensionObject */
{
    UA_TYPENAME("ExtensionObject") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {22LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ExtensionObject), /* .memSize */
    UA_DATATYPEKIND_EXTENSIONOBJECT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ExtensionObject_members  /* .members */
},
/* DataValue */
{
    UA_TYPENAME("DataValue") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DataValue), /* .memSize */
    UA_DATATYPEKIND_DATAVALUE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    DataValue_members  /* .members */
},
/* Variant */
{
    UA_TYPENAME("Variant") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Variant), /* .memSize */
    UA_DATATYPEKIND_VARIANT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Variant_members  /* .members */
},
/* DiagnosticInfo */
{
    UA_TYPENAME("DiagnosticInfo") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DiagnosticInfo), /* .memSize */
    UA_DATATYPEKIND_DIAGNOSTICINFO, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    DiagnosticInfo_members  /* .members */
},
/* NamingRuleType */
{
    UA_TYPENAME("NamingRuleType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {120LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_NamingRuleType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    NamingRuleType_members  /* .members */
},
/* Enumeration */
{
    UA_TYPENAME("Enumeration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {29LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Enumeration), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    Enumeration_members  /* .members */
},
/* ImageBMP */
{
    UA_TYPENAME("ImageBMP") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {2000LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ImageBMP), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ImageBMP_members  /* .members */
},
/* ImageGIF */
{
    UA_TYPENAME("ImageGIF") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {2001LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ImageGIF), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ImageGIF_members  /* .members */
},
/* ImageJPG */
{
    UA_TYPENAME("ImageJPG") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {2002LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ImageJPG), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ImageJPG_members  /* .members */
},
/* ImagePNG */
{
    UA_TYPENAME("ImagePNG") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {2003LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ImagePNG), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ImagePNG_members  /* .members */
},
/* AudioDataType */
{
    UA_TYPENAME("AudioDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {16307LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_AudioDataType), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    AudioDataType_members  /* .members */
},
/* UriString */
{
    UA_TYPENAME("UriString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23751LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UriString), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    UriString_members  /* .members */
},
/* BitFieldMaskDataType */
{
    UA_TYPENAME("BitFieldMaskDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11737LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_BitFieldMaskDataType), /* .memSize */
    UA_DATATYPEKIND_UINT64, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    BitFieldMaskDataType_members  /* .members */
},
/* SemanticVersionString */
{
    UA_TYPENAME("SemanticVersionString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24263LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_SemanticVersionString), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    SemanticVersionString_members  /* .members */
},
/* KeyValuePair */
{
    UA_TYPENAME("KeyValuePair") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14533LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14846LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14802LU}}, /* .xmlEncodingId */
    sizeof(UA_KeyValuePair), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    KeyValuePair_members  /* .members */
},
/* AdditionalParametersType */
{
    UA_TYPENAME("AdditionalParametersType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {16313LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {17537LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {17541LU}}, /* .xmlEncodingId */
    sizeof(UA_AdditionalParametersType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    AdditionalParametersType_members  /* .members */
},
/* EphemeralKeyType */
{
    UA_TYPENAME("EphemeralKeyType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17548LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {17549LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {17553LU}}, /* .xmlEncodingId */
    sizeof(UA_EphemeralKeyType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    EphemeralKeyType_members  /* .members */
},
/* RationalNumber */
{
    UA_TYPENAME("RationalNumber") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {18806LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {18815LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {18851LU}}, /* .xmlEncodingId */
    sizeof(UA_RationalNumber), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RationalNumber_members  /* .members */
},
/* ThreeDVector */
{
    UA_TYPENAME("ThreeDVector") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {18808LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {18817LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {18853LU}}, /* .xmlEncodingId */
    sizeof(UA_ThreeDVector), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ThreeDVector_members  /* .members */
},
/* ThreeDCartesianCoordinates */
{
    UA_TYPENAME("ThreeDCartesianCoordinates") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {18810LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {18819LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {18855LU}}, /* .xmlEncodingId */
    sizeof(UA_ThreeDCartesianCoordinates), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ThreeDCartesianCoordinates_members  /* .members */
},
/* ThreeDOrientation */
{
    UA_TYPENAME("ThreeDOrientation") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {18812LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {18821LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {18857LU}}, /* .xmlEncodingId */
    sizeof(UA_ThreeDOrientation), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ThreeDOrientation_members  /* .members */
},
/* ThreeDFrame */
{
    UA_TYPENAME("ThreeDFrame") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {18814LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {18823LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {18859LU}}, /* .xmlEncodingId */
    sizeof(UA_ThreeDFrame), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ThreeDFrame_members  /* .members */
},
/* OpenFileMode */
{
    UA_TYPENAME("OpenFileMode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11939LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_OpenFileMode), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    OpenFileMode_members  /* .members */
},
/* IdentityCriteriaType */
{
    UA_TYPENAME("IdentityCriteriaType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15632LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_IdentityCriteriaType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    8, /* .membersSize */
    IdentityCriteriaType_members  /* .members */
},
/* IdentityMappingRuleType */
{
    UA_TYPENAME("IdentityMappingRuleType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15634LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15736LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15728LU}}, /* .xmlEncodingId */
    sizeof(UA_IdentityMappingRuleType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    IdentityMappingRuleType_members  /* .members */
},
/* CurrencyUnitType */
{
    UA_TYPENAME("CurrencyUnitType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23498LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23507LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23520LU}}, /* .xmlEncodingId */
    sizeof(UA_CurrencyUnitType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    CurrencyUnitType_members  /* .members */
},
/* TrustListMasks */
{
    UA_TYPENAME("TrustListMasks") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12552LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TrustListMasks), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    6, /* .membersSize */
    TrustListMasks_members  /* .members */
},
/* TrustListDataType */
{
    UA_TYPENAME("TrustListDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12554LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12680LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12676LU}}, /* .xmlEncodingId */
    sizeof(UA_TrustListDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    TrustListDataType_members  /* .members */
},
/* DecimalDataType */
{
    UA_TYPENAME("DecimalDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17861LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {17863LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {17862LU}}, /* .xmlEncodingId */
    sizeof(UA_DecimalDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DecimalDataType_members  /* .members */
},
/* DataTypeDescription */
{
    UA_TYPENAME("DataTypeDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14525LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {125LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14796LU}}, /* .xmlEncodingId */
    sizeof(UA_DataTypeDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DataTypeDescription_members  /* .members */
},
/* SimpleTypeDescription */
{
    UA_TYPENAME("SimpleTypeDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15005LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15421LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15529LU}}, /* .xmlEncodingId */
    sizeof(UA_SimpleTypeDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    SimpleTypeDescription_members  /* .members */
},
/* PortableQualifiedName */
{
    UA_TYPENAME("PortableQualifiedName") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24105LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {24108LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {24120LU}}, /* .xmlEncodingId */
    sizeof(UA_PortableQualifiedName), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    PortableQualifiedName_members  /* .members */
},
/* PortableNodeId */
{
    UA_TYPENAME("PortableNodeId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24106LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {24109LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {24121LU}}, /* .xmlEncodingId */
    sizeof(UA_PortableNodeId), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    PortableNodeId_members  /* .members */
},
/* UnsignedRationalNumber */
{
    UA_TYPENAME("UnsignedRationalNumber") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24107LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {24110LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {24122LU}}, /* .xmlEncodingId */
    sizeof(UA_UnsignedRationalNumber), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    UnsignedRationalNumber_members  /* .members */
},
/* PubSubState */
{
    UA_TYPENAME("PubSubState") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14647LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_PubSubState), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    PubSubState_members  /* .members */
},
/* DataSetFieldFlags */
{
    UA_TYPENAME("DataSetFieldFlags") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15904LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DataSetFieldFlags), /* .memSize */
    UA_DATATYPEKIND_UINT16, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    DataSetFieldFlags_members  /* .members */
},
/* ConfigurationVersionDataType */
{
    UA_TYPENAME("ConfigurationVersionDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14593LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14847LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14803LU}}, /* .xmlEncodingId */
    sizeof(UA_ConfigurationVersionDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ConfigurationVersionDataType_members  /* .members */
},
/* PublishedVariableDataType */
{
    UA_TYPENAME("PublishedVariableDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14273LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14323LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14319LU}}, /* .xmlEncodingId */
    sizeof(UA_PublishedVariableDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    8, /* .membersSize */
    PublishedVariableDataType_members  /* .members */
},
/* PublishedDataItemsDataType */
{
    UA_TYPENAME("PublishedDataItemsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15581LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15679LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15953LU}}, /* .xmlEncodingId */
    sizeof(UA_PublishedDataItemsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    PublishedDataItemsDataType_members  /* .members */
},
/* PublishedDataSetCustomSourceDataType */
{
    UA_TYPENAME("PublishedDataSetCustomSourceDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25269LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {25529LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {25545LU}}, /* .xmlEncodingId */
    sizeof(UA_PublishedDataSetCustomSourceDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    PublishedDataSetCustomSourceDataType_members  /* .members */
},
/* DataSetFieldContentMask */
{
    UA_TYPENAME("DataSetFieldContentMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15583LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DataSetFieldContentMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    DataSetFieldContentMask_members  /* .members */
},
/* DataSetWriterDataType */
{
    UA_TYPENAME("DataSetWriterDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15597LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15682LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15955LU}}, /* .xmlEncodingId */
    sizeof(UA_DataSetWriterDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    DataSetWriterDataType_members  /* .members */
},
/* NetworkAddressDataType */
{
    UA_TYPENAME("NetworkAddressDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15502LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {21151LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {21175LU}}, /* .xmlEncodingId */
    sizeof(UA_NetworkAddressDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    NetworkAddressDataType_members  /* .members */
},
/* NetworkAddressUrlDataType */
{
    UA_TYPENAME("NetworkAddressUrlDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15510LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {21152LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {21176LU}}, /* .xmlEncodingId */
    sizeof(UA_NetworkAddressUrlDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    NetworkAddressUrlDataType_members  /* .members */
},
/* OverrideValueHandling */
{
    UA_TYPENAME("OverrideValueHandling") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15874LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_OverrideValueHandling), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    OverrideValueHandling_members  /* .members */
},
/* StandaloneSubscribedDataSetRefDataType */
{
    UA_TYPENAME("StandaloneSubscribedDataSetRefDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23599LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23851LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23919LU}}, /* .xmlEncodingId */
    sizeof(UA_StandaloneSubscribedDataSetRefDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    StandaloneSubscribedDataSetRefDataType_members  /* .members */
},
/* DataSetOrderingType */
{
    UA_TYPENAME("DataSetOrderingType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {20408LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DataSetOrderingType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    DataSetOrderingType_members  /* .members */
},
/* UadpNetworkMessageContentMask */
{
    UA_TYPENAME("UadpNetworkMessageContentMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15642LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UadpNetworkMessageContentMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UadpNetworkMessageContentMask_members  /* .members */
},
/* UadpWriterGroupMessageDataType */
{
    UA_TYPENAME("UadpWriterGroupMessageDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15645LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15715LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16014LU}}, /* .xmlEncodingId */
    sizeof(UA_UadpWriterGroupMessageDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    UadpWriterGroupMessageDataType_members  /* .members */
},
/* UadpDataSetMessageContentMask */
{
    UA_TYPENAME("UadpDataSetMessageContentMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15646LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UadpDataSetMessageContentMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UadpDataSetMessageContentMask_members  /* .members */
},
/* UadpDataSetWriterMessageDataType */
{
    UA_TYPENAME("UadpDataSetWriterMessageDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15652LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15717LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16015LU}}, /* .xmlEncodingId */
    sizeof(UA_UadpDataSetWriterMessageDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    UadpDataSetWriterMessageDataType_members  /* .members */
},
/* UadpDataSetReaderMessageDataType */
{
    UA_TYPENAME("UadpDataSetReaderMessageDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15653LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15718LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16016LU}}, /* .xmlEncodingId */
    sizeof(UA_UadpDataSetReaderMessageDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    UadpDataSetReaderMessageDataType_members  /* .members */
},
/* JsonNetworkMessageContentMask */
{
    UA_TYPENAME("JsonNetworkMessageContentMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15654LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_JsonNetworkMessageContentMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    JsonNetworkMessageContentMask_members  /* .members */
},
/* JsonWriterGroupMessageDataType */
{
    UA_TYPENAME("JsonWriterGroupMessageDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15657LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15719LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16017LU}}, /* .xmlEncodingId */
    sizeof(UA_JsonWriterGroupMessageDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    JsonWriterGroupMessageDataType_members  /* .members */
},
/* JsonDataSetMessageContentMask */
{
    UA_TYPENAME("JsonDataSetMessageContentMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15658LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_JsonDataSetMessageContentMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    JsonDataSetMessageContentMask_members  /* .members */
},
/* JsonDataSetWriterMessageDataType */
{
    UA_TYPENAME("JsonDataSetWriterMessageDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15664LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15724LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16018LU}}, /* .xmlEncodingId */
    sizeof(UA_JsonDataSetWriterMessageDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    JsonDataSetWriterMessageDataType_members  /* .members */
},
/* JsonDataSetReaderMessageDataType */
{
    UA_TYPENAME("JsonDataSetReaderMessageDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15665LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15725LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16019LU}}, /* .xmlEncodingId */
    sizeof(UA_JsonDataSetReaderMessageDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    JsonDataSetReaderMessageDataType_members  /* .members */
},
/* TransmitQosPriorityDataType */
{
    UA_TYPENAME("TransmitQosPriorityDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23605LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23857LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23925LU}}, /* .xmlEncodingId */
    sizeof(UA_TransmitQosPriorityDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    TransmitQosPriorityDataType_members  /* .members */
},
/* ReceiveQosPriorityDataType */
{
    UA_TYPENAME("ReceiveQosPriorityDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23609LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23861LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23929LU}}, /* .xmlEncodingId */
    sizeof(UA_ReceiveQosPriorityDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ReceiveQosPriorityDataType_members  /* .members */
},
/* DatagramConnectionTransportDataType */
{
    UA_TYPENAME("DatagramConnectionTransportDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17467LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {17468LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {17472LU}}, /* .xmlEncodingId */
    sizeof(UA_DatagramConnectionTransportDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    DatagramConnectionTransportDataType_members  /* .members */
},
/* DatagramConnectionTransport2DataType */
{
    UA_TYPENAME("DatagramConnectionTransport2DataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23612LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23864LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23932LU}}, /* .xmlEncodingId */
    sizeof(UA_DatagramConnectionTransport2DataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    DatagramConnectionTransport2DataType_members  /* .members */
},
/* DatagramWriterGroupTransportDataType */
{
    UA_TYPENAME("DatagramWriterGroupTransportDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15532LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {21155LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {21179LU}}, /* .xmlEncodingId */
    sizeof(UA_DatagramWriterGroupTransportDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DatagramWriterGroupTransportDataType_members  /* .members */
},
/* DatagramWriterGroupTransport2DataType */
{
    UA_TYPENAME("DatagramWriterGroupTransport2DataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23613LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23865LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23933LU}}, /* .xmlEncodingId */
    sizeof(UA_DatagramWriterGroupTransport2DataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    DatagramWriterGroupTransport2DataType_members  /* .members */
},
/* DatagramDataSetReaderTransportDataType */
{
    UA_TYPENAME("DatagramDataSetReaderTransportDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23614LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23866LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23934LU}}, /* .xmlEncodingId */
    sizeof(UA_DatagramDataSetReaderTransportDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    DatagramDataSetReaderTransportDataType_members  /* .members */
},
/* BrokerConnectionTransportDataType */
{
    UA_TYPENAME("BrokerConnectionTransportDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15007LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15479LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15579LU}}, /* .xmlEncodingId */
    sizeof(UA_BrokerConnectionTransportDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    BrokerConnectionTransportDataType_members  /* .members */
},
/* BrokerTransportQualityOfService */
{
    UA_TYPENAME("BrokerTransportQualityOfService") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15008LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_BrokerTransportQualityOfService), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    BrokerTransportQualityOfService_members  /* .members */
},
/* BrokerWriterGroupTransportDataType */
{
    UA_TYPENAME("BrokerWriterGroupTransportDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15667LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15727LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16021LU}}, /* .xmlEncodingId */
    sizeof(UA_BrokerWriterGroupTransportDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    BrokerWriterGroupTransportDataType_members  /* .members */
},
/* BrokerDataSetWriterTransportDataType */
{
    UA_TYPENAME("BrokerDataSetWriterTransportDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15669LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15729LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16022LU}}, /* .xmlEncodingId */
    sizeof(UA_BrokerDataSetWriterTransportDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    BrokerDataSetWriterTransportDataType_members  /* .members */
},
/* BrokerDataSetReaderTransportDataType */
{
    UA_TYPENAME("BrokerDataSetReaderTransportDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15670LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15733LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16023LU}}, /* .xmlEncodingId */
    sizeof(UA_BrokerDataSetReaderTransportDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    BrokerDataSetReaderTransportDataType_members  /* .members */
},
/* PubSubConfigurationRefMask */
{
    UA_TYPENAME("PubSubConfigurationRefMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25517LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_PubSubConfigurationRefMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    PubSubConfigurationRefMask_members  /* .members */
},
/* PubSubConfigurationRefDataType */
{
    UA_TYPENAME("PubSubConfigurationRefDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25519LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {25531LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {25547LU}}, /* .xmlEncodingId */
    sizeof(UA_PubSubConfigurationRefDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    PubSubConfigurationRefDataType_members  /* .members */
},
/* PubSubConfigurationValueDataType */
{
    UA_TYPENAME("PubSubConfigurationValueDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25520LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {25532LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {25548LU}}, /* .xmlEncodingId */
    sizeof(UA_PubSubConfigurationValueDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    PubSubConfigurationValueDataType_members  /* .members */
},
/* DiagnosticsLevel */
{
    UA_TYPENAME("DiagnosticsLevel") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {19723LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DiagnosticsLevel), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    DiagnosticsLevel_members  /* .members */
},
/* PubSubDiagnosticsCounterClassification */
{
    UA_TYPENAME("PubSubDiagnosticsCounterClassification") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {19730LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_PubSubDiagnosticsCounterClassification), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    2, /* .membersSize */
    PubSubDiagnosticsCounterClassification_members  /* .members */
},
/* AliasNameDataType */
{
    UA_TYPENAME("AliasNameDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23468LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23499LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23505LU}}, /* .xmlEncodingId */
    sizeof(UA_AliasNameDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    AliasNameDataType_members  /* .members */
},
/* PasswordOptionsMask */
{
    UA_TYPENAME("PasswordOptionsMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24277LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_PasswordOptionsMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    PasswordOptionsMask_members  /* .members */
},
/* UserConfigurationMask */
{
    UA_TYPENAME("UserConfigurationMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24279LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UserConfigurationMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UserConfigurationMask_members  /* .members */
},
/* UserManagementDataType */
{
    UA_TYPENAME("UserManagementDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24281LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {24292LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {24296LU}}, /* .xmlEncodingId */
    sizeof(UA_UserManagementDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    UserManagementDataType_members  /* .members */
},
/* Duplex */
{
    UA_TYPENAME("Duplex") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24210LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Duplex), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    Duplex_members  /* .members */
},
/* InterfaceAdminStatus */
{
    UA_TYPENAME("InterfaceAdminStatus") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24212LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_InterfaceAdminStatus), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    InterfaceAdminStatus_members  /* .members */
},
/* InterfaceOperStatus */
{
    UA_TYPENAME("InterfaceOperStatus") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24214LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_InterfaceOperStatus), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    7, /* .membersSize */
    InterfaceOperStatus_members  /* .members */
},
/* NegotiationStatus */
{
    UA_TYPENAME("NegotiationStatus") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24216LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_NegotiationStatus), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    NegotiationStatus_members  /* .members */
},
/* TsnFailureCode */
{
    UA_TYPENAME("TsnFailureCode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24218LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TsnFailureCode), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    26, /* .membersSize */
    TsnFailureCode_members  /* .members */
},
/* TsnStreamState */
{
    UA_TYPENAME("TsnStreamState") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24220LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TsnStreamState), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    TsnStreamState_members  /* .members */
},
/* TsnTalkerStatus */
{
    UA_TYPENAME("TsnTalkerStatus") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24222LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TsnTalkerStatus), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    TsnTalkerStatus_members  /* .members */
},
/* TsnListenerStatus */
{
    UA_TYPENAME("TsnListenerStatus") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24224LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TsnListenerStatus), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    TsnListenerStatus_members  /* .members */
},
/* PriorityMappingEntryType */
{
    UA_TYPENAME("PriorityMappingEntryType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25220LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {25239LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {25243LU}}, /* .xmlEncodingId */
    sizeof(UA_PriorityMappingEntryType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    PriorityMappingEntryType_members  /* .members */
},
/* IdType */
{
    UA_TYPENAME("IdType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {256LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_IdType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    IdType_members  /* .members */
},
/* NodeClass */
{
    UA_TYPENAME("NodeClass") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {257LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_NodeClass), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    9, /* .membersSize */
    NodeClass_members  /* .members */
},
/* PermissionType */
{
    UA_TYPENAME("PermissionType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {94LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_PermissionType), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    PermissionType_members  /* .members */
},
/* AccessLevelType */
{
    UA_TYPENAME("AccessLevelType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15031LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_AccessLevelType), /* .memSize */
    UA_DATATYPEKIND_BYTE, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    AccessLevelType_members  /* .members */
},
/* AccessLevelExType */
{
    UA_TYPENAME("AccessLevelExType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15406LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_AccessLevelExType), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    AccessLevelExType_members  /* .members */
},
/* EventNotifierType */
{
    UA_TYPENAME("EventNotifierType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15033LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_EventNotifierType), /* .memSize */
    UA_DATATYPEKIND_BYTE, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    EventNotifierType_members  /* .members */
},
/* AccessRestrictionType */
{
    UA_TYPENAME("AccessRestrictionType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {95LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_AccessRestrictionType), /* .memSize */
    UA_DATATYPEKIND_UINT16, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    AccessRestrictionType_members  /* .members */
},
/* RolePermissionType */
{
    UA_TYPENAME("RolePermissionType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {96LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {128LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16126LU}}, /* .xmlEncodingId */
    sizeof(UA_RolePermissionType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RolePermissionType_members  /* .members */
},
/* StructureType */
{
    UA_TYPENAME("StructureType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {98LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_StructureType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    StructureType_members  /* .members */
},
/* StructureField */
{
    UA_TYPENAME("StructureField") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {101LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14844LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14800LU}}, /* .xmlEncodingId */
    sizeof(UA_StructureField), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    StructureField_members  /* .members */
},
/* StructureDefinition */
{
    UA_TYPENAME("StructureDefinition") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {99LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {122LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14798LU}}, /* .xmlEncodingId */
    sizeof(UA_StructureDefinition), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    StructureDefinition_members  /* .members */
},
/* ReferenceNode */
{
    UA_TYPENAME("ReferenceNode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {285LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {287LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {286LU}}, /* .xmlEncodingId */
    sizeof(UA_ReferenceNode), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ReferenceNode_members  /* .members */
},
/* Argument */
{
    UA_TYPENAME("Argument") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {296LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {298LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {297LU}}, /* .xmlEncodingId */
    sizeof(UA_Argument), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    Argument_members  /* .members */
},
/* EnumValueType */
{
    UA_TYPENAME("EnumValueType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {7594LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {8251LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {7616LU}}, /* .xmlEncodingId */
    sizeof(UA_EnumValueType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    EnumValueType_members  /* .members */
},
/* EnumField */
{
    UA_TYPENAME("EnumField") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {102LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14845LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14801LU}}, /* .xmlEncodingId */
    sizeof(UA_EnumField), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    EnumField_members  /* .members */
},
/* OptionSet */
{
    UA_TYPENAME("OptionSet") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12755LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12765LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12757LU}}, /* .xmlEncodingId */
    sizeof(UA_OptionSet), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    OptionSet_members  /* .members */
},
/* NormalizedString */
{
    UA_TYPENAME("NormalizedString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12877LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_NormalizedString), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    NormalizedString_members  /* .members */
},
/* DecimalString */
{
    UA_TYPENAME("DecimalString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12878LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DecimalString), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    DecimalString_members  /* .members */
},
/* DurationString */
{
    UA_TYPENAME("DurationString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12879LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DurationString), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    DurationString_members  /* .members */
},
/* TimeString */
{
    UA_TYPENAME("TimeString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12880LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TimeString), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    TimeString_members  /* .members */
},
/* DateString */
{
    UA_TYPENAME("DateString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12881LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DateString), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    DateString_members  /* .members */
},
/* Duration */
{
    UA_TYPENAME("Duration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {290LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Duration), /* .memSize */
    UA_DATATYPEKIND_DOUBLE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Duration_members  /* .members */
},
/* UtcTime */
{
    UA_TYPENAME("UtcTime") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {294LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UtcTime), /* .memSize */
    UA_DATATYPEKIND_DATETIME, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    UtcTime_members  /* .members */
},
/* LocaleId */
{
    UA_TYPENAME("LocaleId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {295LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_LocaleId), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    LocaleId_members  /* .members */
},
/* TimeZoneDataType */
{
    UA_TYPENAME("TimeZoneDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {8912LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {8917LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {8913LU}}, /* .xmlEncodingId */
    sizeof(UA_TimeZoneDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TimeZoneDataType_members  /* .members */
},
/* Index */
{
    UA_TYPENAME("Index") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17588LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Index), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Index_members  /* .members */
},
/* IntegerId */
{
    UA_TYPENAME("IntegerId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {288LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_IntegerId), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    IntegerId_members  /* .members */
},
/* ApplicationType */
{
    UA_TYPENAME("ApplicationType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {307LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ApplicationType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    ApplicationType_members  /* .members */
},
/* ApplicationDescription */
{
    UA_TYPENAME("ApplicationDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {308LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {310LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {309LU}}, /* .xmlEncodingId */
    sizeof(UA_ApplicationDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ApplicationDescription_members  /* .members */
},
/* RequestHeader */
{
    UA_TYPENAME("RequestHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {389LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {391LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {390LU}}, /* .xmlEncodingId */
    sizeof(UA_RequestHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    RequestHeader_members  /* .members */
},
/* ResponseHeader */
{
    UA_TYPENAME("ResponseHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {392LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {394LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {393LU}}, /* .xmlEncodingId */
    sizeof(UA_ResponseHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ResponseHeader_members  /* .members */
},
/* VersionTime */
{
    UA_TYPENAME("VersionTime") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {20998LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_VersionTime), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    VersionTime_members  /* .members */
},
/* ServiceFault */
{
    UA_TYPENAME("ServiceFault") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {395LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {397LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {396LU}}, /* .xmlEncodingId */
    sizeof(UA_ServiceFault), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ServiceFault_members  /* .members */
},
/* SessionlessInvokeRequestType */
{
    UA_TYPENAME("SessionlessInvokeRequestType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15901LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15903LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15902LU}}, /* .xmlEncodingId */
    sizeof(UA_SessionlessInvokeRequestType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    SessionlessInvokeRequestType_members  /* .members */
},
/* SessionlessInvokeResponseType */
{
    UA_TYPENAME("SessionlessInvokeResponseType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {20999LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {21001LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {21000LU}}, /* .xmlEncodingId */
    sizeof(UA_SessionlessInvokeResponseType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    SessionlessInvokeResponseType_members  /* .members */
},
/* FindServersRequest */
{
    UA_TYPENAME("FindServersRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {420LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {422LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {421LU}}, /* .xmlEncodingId */
    sizeof(UA_FindServersRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    FindServersRequest_members  /* .members */
},
/* FindServersResponse */
{
    UA_TYPENAME("FindServersResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {423LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {425LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {424LU}}, /* .xmlEncodingId */
    sizeof(UA_FindServersResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    FindServersResponse_members  /* .members */
},
/* ServerOnNetwork */
{
    UA_TYPENAME("ServerOnNetwork") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12189LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12207LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12195LU}}, /* .xmlEncodingId */
    sizeof(UA_ServerOnNetwork), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ServerOnNetwork_members  /* .members */
},
/* FindServersOnNetworkRequest */
{
    UA_TYPENAME("FindServersOnNetworkRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12190LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12208LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12196LU}}, /* .xmlEncodingId */
    sizeof(UA_FindServersOnNetworkRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    FindServersOnNetworkRequest_members  /* .members */
},
/* FindServersOnNetworkResponse */
{
    UA_TYPENAME("FindServersOnNetworkResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12191LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12209LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12197LU}}, /* .xmlEncodingId */
    sizeof(UA_FindServersOnNetworkResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    FindServersOnNetworkResponse_members  /* .members */
},
/* ApplicationInstanceCertificate */
{
    UA_TYPENAME("ApplicationInstanceCertificate") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {311LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ApplicationInstanceCertificate), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ApplicationInstanceCertificate_members  /* .members */
},
/* MessageSecurityMode */
{
    UA_TYPENAME("MessageSecurityMode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {302LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_MessageSecurityMode), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    MessageSecurityMode_members  /* .members */
},
/* UserTokenType */
{
    UA_TYPENAME("UserTokenType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {303LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_UserTokenType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    UserTokenType_members  /* .members */
},
/* UserTokenPolicy */
{
    UA_TYPENAME("UserTokenPolicy") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {304LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {306LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {305LU}}, /* .xmlEncodingId */
    sizeof(UA_UserTokenPolicy), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    UserTokenPolicy_members  /* .members */
},
/* EndpointDescription */
{
    UA_TYPENAME("EndpointDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {312LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {314LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {313LU}}, /* .xmlEncodingId */
    sizeof(UA_EndpointDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    8, /* .membersSize */
    EndpointDescription_members  /* .members */
},
/* GetEndpointsRequest */
{
    UA_TYPENAME("GetEndpointsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {426LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {428LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {427LU}}, /* .xmlEncodingId */
    sizeof(UA_GetEndpointsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    GetEndpointsRequest_members  /* .members */
},
/* GetEndpointsResponse */
{
    UA_TYPENAME("GetEndpointsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {429LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {431LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {430LU}}, /* .xmlEncodingId */
    sizeof(UA_GetEndpointsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    GetEndpointsResponse_members  /* .members */
},
/* RegisteredServer */
{
    UA_TYPENAME("RegisteredServer") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {432LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {434LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {433LU}}, /* .xmlEncodingId */
    sizeof(UA_RegisteredServer), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    8, /* .membersSize */
    RegisteredServer_members  /* .members */
},
/* RegisterServerRequest */
{
    UA_TYPENAME("RegisterServerRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {435LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {437LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {436LU}}, /* .xmlEncodingId */
    sizeof(UA_RegisterServerRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RegisterServerRequest_members  /* .members */
},
/* RegisterServerResponse */
{
    UA_TYPENAME("RegisterServerResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {438LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {440LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {439LU}}, /* .xmlEncodingId */
    sizeof(UA_RegisterServerResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    RegisterServerResponse_members  /* .members */
},
/* MdnsDiscoveryConfiguration */
{
    UA_TYPENAME("MdnsDiscoveryConfiguration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12891LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12901LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12893LU}}, /* .xmlEncodingId */
    sizeof(UA_MdnsDiscoveryConfiguration), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    MdnsDiscoveryConfiguration_members  /* .members */
},
/* RegisterServer2Request */
{
    UA_TYPENAME("RegisterServer2Request") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12193LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12211LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12199LU}}, /* .xmlEncodingId */
    sizeof(UA_RegisterServer2Request), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    RegisterServer2Request_members  /* .members */
},
/* RegisterServer2Response */
{
    UA_TYPENAME("RegisterServer2Response") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12194LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12212LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12200LU}}, /* .xmlEncodingId */
    sizeof(UA_RegisterServer2Response), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    RegisterServer2Response_members  /* .members */
},
/* SecurityTokenRequestType */
{
    UA_TYPENAME("SecurityTokenRequestType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {315LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_SecurityTokenRequestType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    2, /* .membersSize */
    SecurityTokenRequestType_members  /* .members */
},
/* ChannelSecurityToken */
{
    UA_TYPENAME("ChannelSecurityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {441LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {443LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {442LU}}, /* .xmlEncodingId */
    sizeof(UA_ChannelSecurityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ChannelSecurityToken_members  /* .members */
},
/* OpenSecureChannelRequest */
{
    UA_TYPENAME("OpenSecureChannelRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {444LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {446LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {445LU}}, /* .xmlEncodingId */
    sizeof(UA_OpenSecureChannelRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    OpenSecureChannelRequest_members  /* .members */
},
/* OpenSecureChannelResponse */
{
    UA_TYPENAME("OpenSecureChannelResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {447LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {449LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {448LU}}, /* .xmlEncodingId */
    sizeof(UA_OpenSecureChannelResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    OpenSecureChannelResponse_members  /* .members */
},
/* CloseSecureChannelRequest */
{
    UA_TYPENAME("CloseSecureChannelRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {450LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {452LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {451LU}}, /* .xmlEncodingId */
    sizeof(UA_CloseSecureChannelRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    CloseSecureChannelRequest_members  /* .members */
},
/* CloseSecureChannelResponse */
{
    UA_TYPENAME("CloseSecureChannelResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {453LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {455LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {454LU}}, /* .xmlEncodingId */
    sizeof(UA_CloseSecureChannelResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    CloseSecureChannelResponse_members  /* .members */
},
/* SignedSoftwareCertificate */
{
    UA_TYPENAME("SignedSoftwareCertificate") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {344LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {346LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {345LU}}, /* .xmlEncodingId */
    sizeof(UA_SignedSoftwareCertificate), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SignedSoftwareCertificate_members  /* .members */
},
/* SessionAuthenticationToken */
{
    UA_TYPENAME("SessionAuthenticationToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {388LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_SessionAuthenticationToken), /* .memSize */
    UA_DATATYPEKIND_NODEID, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    SessionAuthenticationToken_members  /* .members */
},
/* SignatureData */
{
    UA_TYPENAME("SignatureData") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {456LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {458LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {457LU}}, /* .xmlEncodingId */
    sizeof(UA_SignatureData), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SignatureData_members  /* .members */
},
/* CreateSessionRequest */
{
    UA_TYPENAME("CreateSessionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {459LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {461LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {460LU}}, /* .xmlEncodingId */
    sizeof(UA_CreateSessionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    CreateSessionRequest_members  /* .members */
},
/* CreateSessionResponse */
{
    UA_TYPENAME("CreateSessionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {462LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {464LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {463LU}}, /* .xmlEncodingId */
    sizeof(UA_CreateSessionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    CreateSessionResponse_members  /* .members */
},
/* UserIdentityToken */
{
    UA_TYPENAME("UserIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {316LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {318LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {317LU}}, /* .xmlEncodingId */
    sizeof(UA_UserIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    UserIdentityToken_members  /* .members */
},
/* AnonymousIdentityToken */
{
    UA_TYPENAME("AnonymousIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {319LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {321LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {320LU}}, /* .xmlEncodingId */
    sizeof(UA_AnonymousIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    AnonymousIdentityToken_members  /* .members */
},
/* UserNameIdentityToken */
{
    UA_TYPENAME("UserNameIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {322LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {324LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {323LU}}, /* .xmlEncodingId */
    sizeof(UA_UserNameIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    UserNameIdentityToken_members  /* .members */
},
/* X509IdentityToken */
{
    UA_TYPENAME("X509IdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {325LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {327LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {326LU}}, /* .xmlEncodingId */
    sizeof(UA_X509IdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    X509IdentityToken_members  /* .members */
},
/* IssuedIdentityToken */
{
    UA_TYPENAME("IssuedIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {938LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {940LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {939LU}}, /* .xmlEncodingId */
    sizeof(UA_IssuedIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    IssuedIdentityToken_members  /* .members */
},
/* RsaEncryptedSecret */
{
    UA_TYPENAME("RsaEncryptedSecret") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17545LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_RsaEncryptedSecret), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    RsaEncryptedSecret_members  /* .members */
},
/* EccEncryptedSecret */
{
    UA_TYPENAME("EccEncryptedSecret") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17546LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_EccEncryptedSecret), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    EccEncryptedSecret_members  /* .members */
},
/* ActivateSessionRequest */
{
    UA_TYPENAME("ActivateSessionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {465LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {467LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {466LU}}, /* .xmlEncodingId */
    sizeof(UA_ActivateSessionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ActivateSessionRequest_members  /* .members */
},
/* ActivateSessionResponse */
{
    UA_TYPENAME("ActivateSessionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {468LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {470LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {469LU}}, /* .xmlEncodingId */
    sizeof(UA_ActivateSessionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ActivateSessionResponse_members  /* .members */
},
/* CloseSessionRequest */
{
    UA_TYPENAME("CloseSessionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {471LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {473LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {472LU}}, /* .xmlEncodingId */
    sizeof(UA_CloseSessionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CloseSessionRequest_members  /* .members */
},
/* CloseSessionResponse */
{
    UA_TYPENAME("CloseSessionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {474LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {476LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {475LU}}, /* .xmlEncodingId */
    sizeof(UA_CloseSessionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    CloseSessionResponse_members  /* .members */
},
/* CancelRequest */
{
    UA_TYPENAME("CancelRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {477LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {479LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {478LU}}, /* .xmlEncodingId */
    sizeof(UA_CancelRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CancelRequest_members  /* .members */
},
/* CancelResponse */
{
    UA_TYPENAME("CancelResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {480LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {482LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {481LU}}, /* .xmlEncodingId */
    sizeof(UA_CancelResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CancelResponse_members  /* .members */
},
/* NodeAttributesMask */
{
    UA_TYPENAME("NodeAttributesMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {348LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_NodeAttributesMask), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    35, /* .membersSize */
    NodeAttributesMask_members  /* .members */
},
/* NodeAttributes */
{
    UA_TYPENAME("NodeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {349LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {351LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {350LU}}, /* .xmlEncodingId */
    sizeof(UA_NodeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    NodeAttributes_members  /* .members */
},
/* ObjectAttributes */
{
    UA_TYPENAME("ObjectAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {352LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {354LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {353LU}}, /* .xmlEncodingId */
    sizeof(UA_ObjectAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ObjectAttributes_members  /* .members */
},
/* VariableAttributes */
{
    UA_TYPENAME("VariableAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {355LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {357LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {356LU}}, /* .xmlEncodingId */
    sizeof(UA_VariableAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    13, /* .membersSize */
    VariableAttributes_members  /* .members */
},
/* MethodAttributes */
{
    UA_TYPENAME("MethodAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {358LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {360LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {359LU}}, /* .xmlEncodingId */
    sizeof(UA_MethodAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    MethodAttributes_members  /* .members */
},
/* ObjectTypeAttributes */
{
    UA_TYPENAME("ObjectTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {361LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {363LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {362LU}}, /* .xmlEncodingId */
    sizeof(UA_ObjectTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ObjectTypeAttributes_members  /* .members */
},
/* VariableTypeAttributes */
{
    UA_TYPENAME("VariableTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {364LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {366LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {365LU}}, /* .xmlEncodingId */
    sizeof(UA_VariableTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    VariableTypeAttributes_members  /* .members */
},
/* ReferenceTypeAttributes */
{
    UA_TYPENAME("ReferenceTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {367LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {369LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {368LU}}, /* .xmlEncodingId */
    sizeof(UA_ReferenceTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    8, /* .membersSize */
    ReferenceTypeAttributes_members  /* .members */
},
/* DataTypeAttributes */
{
    UA_TYPENAME("DataTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {370LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {372LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {371LU}}, /* .xmlEncodingId */
    sizeof(UA_DataTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    DataTypeAttributes_members  /* .members */
},
/* ViewAttributes */
{
    UA_TYPENAME("ViewAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {373LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {375LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {374LU}}, /* .xmlEncodingId */
    sizeof(UA_ViewAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ViewAttributes_members  /* .members */
},
/* GenericAttributeValue */
{
    UA_TYPENAME("GenericAttributeValue") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17606LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {17610LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {17608LU}}, /* .xmlEncodingId */
    sizeof(UA_GenericAttributeValue), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    GenericAttributeValue_members  /* .members */
},
/* GenericAttributes */
{
    UA_TYPENAME("GenericAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17607LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {17611LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {17609LU}}, /* .xmlEncodingId */
    sizeof(UA_GenericAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    GenericAttributes_members  /* .members */
},
/* AddNodesItem */
{
    UA_TYPENAME("AddNodesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {376LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {378LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {377LU}}, /* .xmlEncodingId */
    sizeof(UA_AddNodesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    AddNodesItem_members  /* .members */
},
/* AddNodesResult */
{
    UA_TYPENAME("AddNodesResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {483LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {485LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {484LU}}, /* .xmlEncodingId */
    sizeof(UA_AddNodesResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    AddNodesResult_members  /* .members */
},
/* AddNodesRequest */
{
    UA_TYPENAME("AddNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {486LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {488LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {487LU}}, /* .xmlEncodingId */
    sizeof(UA_AddNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    AddNodesRequest_members  /* .members */
},
/* AddNodesResponse */
{
    UA_TYPENAME("AddNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {489LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {491LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {490LU}}, /* .xmlEncodingId */
    sizeof(UA_AddNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    AddNodesResponse_members  /* .members */
},
/* AddReferencesItem */
{
    UA_TYPENAME("AddReferencesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {379LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {381LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {380LU}}, /* .xmlEncodingId */
    sizeof(UA_AddReferencesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    AddReferencesItem_members  /* .members */
},
/* AddReferencesRequest */
{
    UA_TYPENAME("AddReferencesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {492LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {494LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {493LU}}, /* .xmlEncodingId */
    sizeof(UA_AddReferencesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    AddReferencesRequest_members  /* .members */
},
/* AddReferencesResponse */
{
    UA_TYPENAME("AddReferencesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {495LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {497LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {496LU}}, /* .xmlEncodingId */
    sizeof(UA_AddReferencesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    AddReferencesResponse_members  /* .members */
},
/* DeleteNodesItem */
{
    UA_TYPENAME("DeleteNodesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {382LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {384LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {383LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteNodesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteNodesItem_members  /* .members */
},
/* DeleteNodesRequest */
{
    UA_TYPENAME("DeleteNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {498LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {500LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {499LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteNodesRequest_members  /* .members */
},
/* DeleteNodesResponse */
{
    UA_TYPENAME("DeleteNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {501LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {503LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {502LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteNodesResponse_members  /* .members */
},
/* DeleteReferencesItem */
{
    UA_TYPENAME("DeleteReferencesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {385LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {387LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {386LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteReferencesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    DeleteReferencesItem_members  /* .members */
},
/* DeleteReferencesRequest */
{
    UA_TYPENAME("DeleteReferencesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {504LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {506LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {505LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteReferencesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteReferencesRequest_members  /* .members */
},
/* DeleteReferencesResponse */
{
    UA_TYPENAME("DeleteReferencesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {507LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {509LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {508LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteReferencesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteReferencesResponse_members  /* .members */
},
/* AttributeWriteMask */
{
    UA_TYPENAME("AttributeWriteMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {347LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_AttributeWriteMask), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    AttributeWriteMask_members  /* .members */
},
/* BrowseDirection */
{
    UA_TYPENAME("BrowseDirection") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {510LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_BrowseDirection), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    BrowseDirection_members  /* .members */
},
/* ViewDescription */
{
    UA_TYPENAME("ViewDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {511LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {513LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {512LU}}, /* .xmlEncodingId */
    sizeof(UA_ViewDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ViewDescription_members  /* .members */
},
/* BrowseDescription */
{
    UA_TYPENAME("BrowseDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {514LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {516LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {515LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowseDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    BrowseDescription_members  /* .members */
},
/* BrowseResultMask */
{
    UA_TYPENAME("BrowseResultMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {517LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_BrowseResultMask), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    10, /* .membersSize */
    BrowseResultMask_members  /* .members */
},
/* ReferenceDescription */
{
    UA_TYPENAME("ReferenceDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {518LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {520LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {519LU}}, /* .xmlEncodingId */
    sizeof(UA_ReferenceDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ReferenceDescription_members  /* .members */
},
/* ContinuationPoint */
{
    UA_TYPENAME("ContinuationPoint") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {521LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ContinuationPoint), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ContinuationPoint_members  /* .members */
},
/* BrowseResult */
{
    UA_TYPENAME("BrowseResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {522LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {524LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {523LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowseResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseResult_members  /* .members */
},
/* BrowseRequest */
{
    UA_TYPENAME("BrowseRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {525LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {527LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {526LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowseRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    BrowseRequest_members  /* .members */
},
/* BrowseResponse */
{
    UA_TYPENAME("BrowseResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {528LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {530LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {529LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowseResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseResponse_members  /* .members */
},
/* BrowseNextRequest */
{
    UA_TYPENAME("BrowseNextRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {531LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {533LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {532LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowseNextRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseNextRequest_members  /* .members */
},
/* BrowseNextResponse */
{
    UA_TYPENAME("BrowseNextResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {534LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {536LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {535LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowseNextResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseNextResponse_members  /* .members */
},
/* RelativePathElement */
{
    UA_TYPENAME("RelativePathElement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {537LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {539LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {538LU}}, /* .xmlEncodingId */
    sizeof(UA_RelativePathElement), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    RelativePathElement_members  /* .members */
},
/* RelativePath */
{
    UA_TYPENAME("RelativePath") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {540LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {542LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {541LU}}, /* .xmlEncodingId */
    sizeof(UA_RelativePath), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    RelativePath_members  /* .members */
},
/* BrowsePath */
{
    UA_TYPENAME("BrowsePath") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {543LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {545LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {544LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowsePath), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    BrowsePath_members  /* .members */
},
/* BrowsePathTarget */
{
    UA_TYPENAME("BrowsePathTarget") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {546LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {548LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {547LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowsePathTarget), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    BrowsePathTarget_members  /* .members */
},
/* BrowsePathResult */
{
    UA_TYPENAME("BrowsePathResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {549LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {551LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {550LU}}, /* .xmlEncodingId */
    sizeof(UA_BrowsePathResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    BrowsePathResult_members  /* .members */
},
/* TranslateBrowsePathsToNodeIdsRequest */
{
    UA_TYPENAME("TranslateBrowsePathsToNodeIdsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {552LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {554LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {553LU}}, /* .xmlEncodingId */
    sizeof(UA_TranslateBrowsePathsToNodeIdsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TranslateBrowsePathsToNodeIdsRequest_members  /* .members */
},
/* TranslateBrowsePathsToNodeIdsResponse */
{
    UA_TYPENAME("TranslateBrowsePathsToNodeIdsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {555LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {557LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {556LU}}, /* .xmlEncodingId */
    sizeof(UA_TranslateBrowsePathsToNodeIdsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    TranslateBrowsePathsToNodeIdsResponse_members  /* .members */
},
/* RegisterNodesRequest */
{
    UA_TYPENAME("RegisterNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {558LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {560LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {559LU}}, /* .xmlEncodingId */
    sizeof(UA_RegisterNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RegisterNodesRequest_members  /* .members */
},
/* RegisterNodesResponse */
{
    UA_TYPENAME("RegisterNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {561LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {563LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {562LU}}, /* .xmlEncodingId */
    sizeof(UA_RegisterNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RegisterNodesResponse_members  /* .members */
},
/* UnregisterNodesRequest */
{
    UA_TYPENAME("UnregisterNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {564LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {566LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {565LU}}, /* .xmlEncodingId */
    sizeof(UA_UnregisterNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    UnregisterNodesRequest_members  /* .members */
},
/* UnregisterNodesResponse */
{
    UA_TYPENAME("UnregisterNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {567LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {569LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {568LU}}, /* .xmlEncodingId */
    sizeof(UA_UnregisterNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    UnregisterNodesResponse_members  /* .members */
},
/* Counter */
{
    UA_TYPENAME("Counter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {289LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_Counter), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Counter_members  /* .members */
},
/* OpaqueNumericRange */
{
    UA_TYPENAME("OpaqueNumericRange") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {291LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_OpaqueNumericRange), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    OpaqueNumericRange_members  /* .members */
},
/* EndpointConfiguration */
{
    UA_TYPENAME("EndpointConfiguration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {331LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {333LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {332LU}}, /* .xmlEncodingId */
    sizeof(UA_EndpointConfiguration), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    EndpointConfiguration_members  /* .members */
},
/* QueryDataDescription */
{
    UA_TYPENAME("QueryDataDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {570LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {572LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {571LU}}, /* .xmlEncodingId */
    sizeof(UA_QueryDataDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    QueryDataDescription_members  /* .members */
},
/* NodeTypeDescription */
{
    UA_TYPENAME("NodeTypeDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {573LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {575LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {574LU}}, /* .xmlEncodingId */
    sizeof(UA_NodeTypeDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    NodeTypeDescription_members  /* .members */
},
/* FilterOperator */
{
    UA_TYPENAME("FilterOperator") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {576LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_FilterOperator), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    18, /* .membersSize */
    FilterOperator_members  /* .members */
},
/* QueryDataSet */
{
    UA_TYPENAME("QueryDataSet") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {577LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {579LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {578LU}}, /* .xmlEncodingId */
    sizeof(UA_QueryDataSet), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    QueryDataSet_members  /* .members */
},
/* NodeReference */
{
    UA_TYPENAME("NodeReference") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {580LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {582LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {581LU}}, /* .xmlEncodingId */
    sizeof(UA_NodeReference), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    NodeReference_members  /* .members */
},
/* ContentFilterElement */
{
    UA_TYPENAME("ContentFilterElement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {583LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {585LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {584LU}}, /* .xmlEncodingId */
    sizeof(UA_ContentFilterElement), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ContentFilterElement_members  /* .members */
},
/* ContentFilter */
{
    UA_TYPENAME("ContentFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {586LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {588LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {587LU}}, /* .xmlEncodingId */
    sizeof(UA_ContentFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ContentFilter_members  /* .members */
},
/* ElementOperand */
{
    UA_TYPENAME("ElementOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {592LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {594LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {593LU}}, /* .xmlEncodingId */
    sizeof(UA_ElementOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ElementOperand_members  /* .members */
},
/* LiteralOperand */
{
    UA_TYPENAME("LiteralOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {595LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {597LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {596LU}}, /* .xmlEncodingId */
    sizeof(UA_LiteralOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    LiteralOperand_members  /* .members */
},
/* AttributeOperand */
{
    UA_TYPENAME("AttributeOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {598LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {600LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {599LU}}, /* .xmlEncodingId */
    sizeof(UA_AttributeOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    AttributeOperand_members  /* .members */
},
/* SimpleAttributeOperand */
{
    UA_TYPENAME("SimpleAttributeOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {601LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {603LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {602LU}}, /* .xmlEncodingId */
    sizeof(UA_SimpleAttributeOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    SimpleAttributeOperand_members  /* .members */
},
/* ContentFilterElementResult */
{
    UA_TYPENAME("ContentFilterElementResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {604LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {606LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {605LU}}, /* .xmlEncodingId */
    sizeof(UA_ContentFilterElementResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ContentFilterElementResult_members  /* .members */
},
/* ContentFilterResult */
{
    UA_TYPENAME("ContentFilterResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {607LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {609LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {608LU}}, /* .xmlEncodingId */
    sizeof(UA_ContentFilterResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ContentFilterResult_members  /* .members */
},
/* ParsingResult */
{
    UA_TYPENAME("ParsingResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {610LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {612LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {611LU}}, /* .xmlEncodingId */
    sizeof(UA_ParsingResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ParsingResult_members  /* .members */
},
/* QueryFirstRequest */
{
    UA_TYPENAME("QueryFirstRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {613LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {615LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {614LU}}, /* .xmlEncodingId */
    sizeof(UA_QueryFirstRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    QueryFirstRequest_members  /* .members */
},
/* QueryFirstResponse */
{
    UA_TYPENAME("QueryFirstResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {616LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {618LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {617LU}}, /* .xmlEncodingId */
    sizeof(UA_QueryFirstResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    QueryFirstResponse_members  /* .members */
},
/* QueryNextRequest */
{
    UA_TYPENAME("QueryNextRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {619LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {621LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {620LU}}, /* .xmlEncodingId */
    sizeof(UA_QueryNextRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    QueryNextRequest_members  /* .members */
},
/* QueryNextResponse */
{
    UA_TYPENAME("QueryNextResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {622LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {624LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {623LU}}, /* .xmlEncodingId */
    sizeof(UA_QueryNextResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    QueryNextResponse_members  /* .members */
},
/* TimestampsToReturn */
{
    UA_TYPENAME("TimestampsToReturn") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {625LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TimestampsToReturn), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    TimestampsToReturn_members  /* .members */
},
/* ReadValueId */
{
    UA_TYPENAME("ReadValueId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {626LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {628LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {627LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadValueId), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ReadValueId_members  /* .members */
},
/* ReadRequest */
{
    UA_TYPENAME("ReadRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {629LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {631LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {630LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ReadRequest_members  /* .members */
},
/* ReadResponse */
{
    UA_TYPENAME("ReadResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {632LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {634LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {633LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ReadResponse_members  /* .members */
},
/* HistoryReadValueId */
{
    UA_TYPENAME("HistoryReadValueId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {635LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {637LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {636LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryReadValueId), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    HistoryReadValueId_members  /* .members */
},
/* HistoryReadResult */
{
    UA_TYPENAME("HistoryReadResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {638LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {640LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {639LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryReadResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryReadResult_members  /* .members */
},
/* ReadRawModifiedDetails */
{
    UA_TYPENAME("ReadRawModifiedDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {647LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {649LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {648LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadRawModifiedDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    ReadRawModifiedDetails_members  /* .members */
},
/* ReadAtTimeDetails */
{
    UA_TYPENAME("ReadAtTimeDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {653LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {655LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {654LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadAtTimeDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ReadAtTimeDetails_members  /* .members */
},
/* ReadAnnotationDataDetails */
{
    UA_TYPENAME("ReadAnnotationDataDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23497LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23500LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23506LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadAnnotationDataDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ReadAnnotationDataDetails_members  /* .members */
},
/* HistoryData */
{
    UA_TYPENAME("HistoryData") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {656LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {658LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {657LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryData), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    HistoryData_members  /* .members */
},
/* HistoryReadRequest */
{
    UA_TYPENAME("HistoryReadRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {662LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {664LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {663LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryReadRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    HistoryReadRequest_members  /* .members */
},
/* HistoryReadResponse */
{
    UA_TYPENAME("HistoryReadResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {665LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {667LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {666LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryReadResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryReadResponse_members  /* .members */
},
/* WriteValue */
{
    UA_TYPENAME("WriteValue") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {668LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {670LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {669LU}}, /* .xmlEncodingId */
    sizeof(UA_WriteValue), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    WriteValue_members  /* .members */
},
/* WriteRequest */
{
    UA_TYPENAME("WriteRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {671LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {673LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {672LU}}, /* .xmlEncodingId */
    sizeof(UA_WriteRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    WriteRequest_members  /* .members */
},
/* WriteResponse */
{
    UA_TYPENAME("WriteResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {674LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {676LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {675LU}}, /* .xmlEncodingId */
    sizeof(UA_WriteResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    WriteResponse_members  /* .members */
},
/* HistoryUpdateDetails */
{
    UA_TYPENAME("HistoryUpdateDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {677LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {679LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {678LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryUpdateDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    HistoryUpdateDetails_members  /* .members */
},
/* HistoryUpdateType */
{
    UA_TYPENAME("HistoryUpdateType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11234LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_HistoryUpdateType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    HistoryUpdateType_members  /* .members */
},
/* PerformUpdateType */
{
    UA_TYPENAME("PerformUpdateType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11293LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_PerformUpdateType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    4, /* .membersSize */
    PerformUpdateType_members  /* .members */
},
/* UpdateDataDetails */
{
    UA_TYPENAME("UpdateDataDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {680LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {682LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {681LU}}, /* .xmlEncodingId */
    sizeof(UA_UpdateDataDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    UpdateDataDetails_members  /* .members */
},
/* UpdateStructureDataDetails */
{
    UA_TYPENAME("UpdateStructureDataDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11295LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {11300LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {11296LU}}, /* .xmlEncodingId */
    sizeof(UA_UpdateStructureDataDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    UpdateStructureDataDetails_members  /* .members */
},
/* DeleteRawModifiedDetails */
{
    UA_TYPENAME("DeleteRawModifiedDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {686LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {688LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {687LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteRawModifiedDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    DeleteRawModifiedDetails_members  /* .members */
},
/* DeleteAtTimeDetails */
{
    UA_TYPENAME("DeleteAtTimeDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {689LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {691LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {690LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteAtTimeDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteAtTimeDetails_members  /* .members */
},
/* DeleteEventDetails */
{
    UA_TYPENAME("DeleteEventDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {692LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {694LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {693LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteEventDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteEventDetails_members  /* .members */
},
/* HistoryUpdateResult */
{
    UA_TYPENAME("HistoryUpdateResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {695LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {697LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {696LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryUpdateResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryUpdateResult_members  /* .members */
},
/* HistoryUpdateRequest */
{
    UA_TYPENAME("HistoryUpdateRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {698LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {700LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {699LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryUpdateRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    HistoryUpdateRequest_members  /* .members */
},
/* HistoryUpdateResponse */
{
    UA_TYPENAME("HistoryUpdateResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {701LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {703LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {702LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryUpdateResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryUpdateResponse_members  /* .members */
},
/* CallMethodRequest */
{
    UA_TYPENAME("CallMethodRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {704LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {706LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {705LU}}, /* .xmlEncodingId */
    sizeof(UA_CallMethodRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    CallMethodRequest_members  /* .members */
},
/* CallMethodResult */
{
    UA_TYPENAME("CallMethodResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {707LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {709LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {708LU}}, /* .xmlEncodingId */
    sizeof(UA_CallMethodResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    CallMethodResult_members  /* .members */
},
/* CallRequest */
{
    UA_TYPENAME("CallRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {710LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {712LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {711LU}}, /* .xmlEncodingId */
    sizeof(UA_CallRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CallRequest_members  /* .members */
},
/* CallResponse */
{
    UA_TYPENAME("CallResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {713LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {715LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {714LU}}, /* .xmlEncodingId */
    sizeof(UA_CallResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    CallResponse_members  /* .members */
},
/* MonitoringMode */
{
    UA_TYPENAME("MonitoringMode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {716LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_MonitoringMode), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    MonitoringMode_members  /* .members */
},
/* DataChangeTrigger */
{
    UA_TYPENAME("DataChangeTrigger") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {717LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DataChangeTrigger), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    DataChangeTrigger_members  /* .members */
},
/* DeadbandType */
{
    UA_TYPENAME("DeadbandType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {718LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_DeadbandType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    DeadbandType_members  /* .members */
},
/* DataChangeFilter */
{
    UA_TYPENAME("DataChangeFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {722LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {724LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {723LU}}, /* .xmlEncodingId */
    sizeof(UA_DataChangeFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DataChangeFilter_members  /* .members */
},
/* EventFilter */
{
    UA_TYPENAME("EventFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {725LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {727LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {726LU}}, /* .xmlEncodingId */
    sizeof(UA_EventFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    EventFilter_members  /* .members */
},
/* AggregateConfiguration */
{
    UA_TYPENAME("AggregateConfiguration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {948LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {950LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {949LU}}, /* .xmlEncodingId */
    sizeof(UA_AggregateConfiguration), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    AggregateConfiguration_members  /* .members */
},
/* AggregateFilter */
{
    UA_TYPENAME("AggregateFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {728LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {730LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {729LU}}, /* .xmlEncodingId */
    sizeof(UA_AggregateFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    AggregateFilter_members  /* .members */
},
/* EventFilterResult */
{
    UA_TYPENAME("EventFilterResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {734LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {736LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {735LU}}, /* .xmlEncodingId */
    sizeof(UA_EventFilterResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    EventFilterResult_members  /* .members */
},
/* AggregateFilterResult */
{
    UA_TYPENAME("AggregateFilterResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {737LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {739LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {738LU}}, /* .xmlEncodingId */
    sizeof(UA_AggregateFilterResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    AggregateFilterResult_members  /* .members */
},
/* MonitoringParameters */
{
    UA_TYPENAME("MonitoringParameters") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {740LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {742LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {741LU}}, /* .xmlEncodingId */
    sizeof(UA_MonitoringParameters), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    MonitoringParameters_members  /* .members */
},
/* MonitoredItemCreateRequest */
{
    UA_TYPENAME("MonitoredItemCreateRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {743LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {745LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {744LU}}, /* .xmlEncodingId */
    sizeof(UA_MonitoredItemCreateRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    MonitoredItemCreateRequest_members  /* .members */
},
/* MonitoredItemCreateResult */
{
    UA_TYPENAME("MonitoredItemCreateResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {746LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {748LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {747LU}}, /* .xmlEncodingId */
    sizeof(UA_MonitoredItemCreateResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    MonitoredItemCreateResult_members  /* .members */
},
/* CreateMonitoredItemsRequest */
{
    UA_TYPENAME("CreateMonitoredItemsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {749LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {751LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {750LU}}, /* .xmlEncodingId */
    sizeof(UA_CreateMonitoredItemsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    CreateMonitoredItemsRequest_members  /* .members */
},
/* CreateMonitoredItemsResponse */
{
    UA_TYPENAME("CreateMonitoredItemsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {752LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {754LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {753LU}}, /* .xmlEncodingId */
    sizeof(UA_CreateMonitoredItemsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    CreateMonitoredItemsResponse_members  /* .members */
},
/* MonitoredItemModifyRequest */
{
    UA_TYPENAME("MonitoredItemModifyRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {755LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {757LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {756LU}}, /* .xmlEncodingId */
    sizeof(UA_MonitoredItemModifyRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    MonitoredItemModifyRequest_members  /* .members */
},
/* MonitoredItemModifyResult */
{
    UA_TYPENAME("MonitoredItemModifyResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {758LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {760LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {759LU}}, /* .xmlEncodingId */
    sizeof(UA_MonitoredItemModifyResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    MonitoredItemModifyResult_members  /* .members */
},
/* ModifyMonitoredItemsRequest */
{
    UA_TYPENAME("ModifyMonitoredItemsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {761LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {763LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {762LU}}, /* .xmlEncodingId */
    sizeof(UA_ModifyMonitoredItemsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ModifyMonitoredItemsRequest_members  /* .members */
},
/* ModifyMonitoredItemsResponse */
{
    UA_TYPENAME("ModifyMonitoredItemsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {764LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {766LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {765LU}}, /* .xmlEncodingId */
    sizeof(UA_ModifyMonitoredItemsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ModifyMonitoredItemsResponse_members  /* .members */
},
/* SetMonitoringModeRequest */
{
    UA_TYPENAME("SetMonitoringModeRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {767LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {769LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {768LU}}, /* .xmlEncodingId */
    sizeof(UA_SetMonitoringModeRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    SetMonitoringModeRequest_members  /* .members */
},
/* SetMonitoringModeResponse */
{
    UA_TYPENAME("SetMonitoringModeResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {770LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {772LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {771LU}}, /* .xmlEncodingId */
    sizeof(UA_SetMonitoringModeResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    SetMonitoringModeResponse_members  /* .members */
},
/* SetTriggeringRequest */
{
    UA_TYPENAME("SetTriggeringRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {773LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {775LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {774LU}}, /* .xmlEncodingId */
    sizeof(UA_SetTriggeringRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    SetTriggeringRequest_members  /* .members */
},
/* SetTriggeringResponse */
{
    UA_TYPENAME("SetTriggeringResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {776LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {778LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {777LU}}, /* .xmlEncodingId */
    sizeof(UA_SetTriggeringResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    SetTriggeringResponse_members  /* .members */
},
/* DeleteMonitoredItemsRequest */
{
    UA_TYPENAME("DeleteMonitoredItemsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {779LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {781LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {780LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteMonitoredItemsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteMonitoredItemsRequest_members  /* .members */
},
/* DeleteMonitoredItemsResponse */
{
    UA_TYPENAME("DeleteMonitoredItemsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {782LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {784LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {783LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteMonitoredItemsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteMonitoredItemsResponse_members  /* .members */
},
/* CreateSubscriptionRequest */
{
    UA_TYPENAME("CreateSubscriptionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {785LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {787LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {786LU}}, /* .xmlEncodingId */
    sizeof(UA_CreateSubscriptionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    CreateSubscriptionRequest_members  /* .members */
},
/* CreateSubscriptionResponse */
{
    UA_TYPENAME("CreateSubscriptionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {788LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {790LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {789LU}}, /* .xmlEncodingId */
    sizeof(UA_CreateSubscriptionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    CreateSubscriptionResponse_members  /* .members */
},
/* ModifySubscriptionRequest */
{
    UA_TYPENAME("ModifySubscriptionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {791LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {793LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {792LU}}, /* .xmlEncodingId */
    sizeof(UA_ModifySubscriptionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ModifySubscriptionRequest_members  /* .members */
},
/* ModifySubscriptionResponse */
{
    UA_TYPENAME("ModifySubscriptionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {794LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {796LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {795LU}}, /* .xmlEncodingId */
    sizeof(UA_ModifySubscriptionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ModifySubscriptionResponse_members  /* .members */
},
/* SetPublishingModeRequest */
{
    UA_TYPENAME("SetPublishingModeRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {797LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {799LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {798LU}}, /* .xmlEncodingId */
    sizeof(UA_SetPublishingModeRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    SetPublishingModeRequest_members  /* .members */
},
/* SetPublishingModeResponse */
{
    UA_TYPENAME("SetPublishingModeResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {800LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {802LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {801LU}}, /* .xmlEncodingId */
    sizeof(UA_SetPublishingModeResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    SetPublishingModeResponse_members  /* .members */
},
/* NotificationMessage */
{
    UA_TYPENAME("NotificationMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {803LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {805LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {804LU}}, /* .xmlEncodingId */
    sizeof(UA_NotificationMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    NotificationMessage_members  /* .members */
},
/* MonitoredItemNotification */
{
    UA_TYPENAME("MonitoredItemNotification") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {806LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {808LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {807LU}}, /* .xmlEncodingId */
    sizeof(UA_MonitoredItemNotification), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    MonitoredItemNotification_members  /* .members */
},
/* EventFieldList */
{
    UA_TYPENAME("EventFieldList") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {917LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {919LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {918LU}}, /* .xmlEncodingId */
    sizeof(UA_EventFieldList), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    EventFieldList_members  /* .members */
},
/* HistoryEventFieldList */
{
    UA_TYPENAME("HistoryEventFieldList") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {920LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {922LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {921LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryEventFieldList), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    HistoryEventFieldList_members  /* .members */
},
/* StatusChangeNotification */
{
    UA_TYPENAME("StatusChangeNotification") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {818LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {820LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {819LU}}, /* .xmlEncodingId */
    sizeof(UA_StatusChangeNotification), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    StatusChangeNotification_members  /* .members */
},
/* SubscriptionAcknowledgement */
{
    UA_TYPENAME("SubscriptionAcknowledgement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {821LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {823LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {822LU}}, /* .xmlEncodingId */
    sizeof(UA_SubscriptionAcknowledgement), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SubscriptionAcknowledgement_members  /* .members */
},
/* PublishRequest */
{
    UA_TYPENAME("PublishRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {824LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {826LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {825LU}}, /* .xmlEncodingId */
    sizeof(UA_PublishRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    PublishRequest_members  /* .members */
},
/* PublishResponse */
{
    UA_TYPENAME("PublishResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {827LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {829LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {828LU}}, /* .xmlEncodingId */
    sizeof(UA_PublishResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    PublishResponse_members  /* .members */
},
/* RepublishRequest */
{
    UA_TYPENAME("RepublishRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {830LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {832LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {831LU}}, /* .xmlEncodingId */
    sizeof(UA_RepublishRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    RepublishRequest_members  /* .members */
},
/* RepublishResponse */
{
    UA_TYPENAME("RepublishResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {833LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {835LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {834LU}}, /* .xmlEncodingId */
    sizeof(UA_RepublishResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RepublishResponse_members  /* .members */
},
/* TransferResult */
{
    UA_TYPENAME("TransferResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {836LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {838LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {837LU}}, /* .xmlEncodingId */
    sizeof(UA_TransferResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TransferResult_members  /* .members */
},
/* TransferSubscriptionsRequest */
{
    UA_TYPENAME("TransferSubscriptionsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {839LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {841LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {840LU}}, /* .xmlEncodingId */
    sizeof(UA_TransferSubscriptionsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    TransferSubscriptionsRequest_members  /* .members */
},
/* TransferSubscriptionsResponse */
{
    UA_TYPENAME("TransferSubscriptionsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {842LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {844LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {843LU}}, /* .xmlEncodingId */
    sizeof(UA_TransferSubscriptionsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    TransferSubscriptionsResponse_members  /* .members */
},
/* DeleteSubscriptionsRequest */
{
    UA_TYPENAME("DeleteSubscriptionsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {845LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {847LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {846LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteSubscriptionsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteSubscriptionsRequest_members  /* .members */
},
/* DeleteSubscriptionsResponse */
{
    UA_TYPENAME("DeleteSubscriptionsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {848LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {850LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {849LU}}, /* .xmlEncodingId */
    sizeof(UA_DeleteSubscriptionsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteSubscriptionsResponse_members  /* .members */
},
/* BuildInfo */
{
    UA_TYPENAME("BuildInfo") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {338LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {340LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {339LU}}, /* .xmlEncodingId */
    sizeof(UA_BuildInfo), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    BuildInfo_members  /* .members */
},
/* RedundancySupport */
{
    UA_TYPENAME("RedundancySupport") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {851LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_RedundancySupport), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    6, /* .membersSize */
    RedundancySupport_members  /* .members */
},
/* ServerState */
{
    UA_TYPENAME("ServerState") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {852LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ServerState), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    8, /* .membersSize */
    ServerState_members  /* .members */
},
/* RedundantServerDataType */
{
    UA_TYPENAME("RedundantServerDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {853LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {855LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {854LU}}, /* .xmlEncodingId */
    sizeof(UA_RedundantServerDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    RedundantServerDataType_members  /* .members */
},
/* EndpointUrlListDataType */
{
    UA_TYPENAME("EndpointUrlListDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11943LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {11957LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {11949LU}}, /* .xmlEncodingId */
    sizeof(UA_EndpointUrlListDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    EndpointUrlListDataType_members  /* .members */
},
/* NetworkGroupDataType */
{
    UA_TYPENAME("NetworkGroupDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11944LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {11958LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {11950LU}}, /* .xmlEncodingId */
    sizeof(UA_NetworkGroupDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    NetworkGroupDataType_members  /* .members */
},
/* SamplingIntervalDiagnosticsDataType */
{
    UA_TYPENAME("SamplingIntervalDiagnosticsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {856LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {858LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {857LU}}, /* .xmlEncodingId */
    sizeof(UA_SamplingIntervalDiagnosticsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    SamplingIntervalDiagnosticsDataType_members  /* .members */
},
/* ServerDiagnosticsSummaryDataType */
{
    UA_TYPENAME("ServerDiagnosticsSummaryDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {859LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {861LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {860LU}}, /* .xmlEncodingId */
    sizeof(UA_ServerDiagnosticsSummaryDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    12, /* .membersSize */
    ServerDiagnosticsSummaryDataType_members  /* .members */
},
/* ServerStatusDataType */
{
    UA_TYPENAME("ServerStatusDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {862LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {864LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {863LU}}, /* .xmlEncodingId */
    sizeof(UA_ServerStatusDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ServerStatusDataType_members  /* .members */
},
/* SessionSecurityDiagnosticsDataType */
{
    UA_TYPENAME("SessionSecurityDiagnosticsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {868LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {870LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {869LU}}, /* .xmlEncodingId */
    sizeof(UA_SessionSecurityDiagnosticsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    SessionSecurityDiagnosticsDataType_members  /* .members */
},
/* ServiceCounterDataType */
{
    UA_TYPENAME("ServiceCounterDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {871LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {873LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {872LU}}, /* .xmlEncodingId */
    sizeof(UA_ServiceCounterDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ServiceCounterDataType_members  /* .members */
},
/* StatusResult */
{
    UA_TYPENAME("StatusResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {299LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {301LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {300LU}}, /* .xmlEncodingId */
    sizeof(UA_StatusResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    StatusResult_members  /* .members */
},
/* SubscriptionDiagnosticsDataType */
{
    UA_TYPENAME("SubscriptionDiagnosticsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {874LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {876LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {875LU}}, /* .xmlEncodingId */
    sizeof(UA_SubscriptionDiagnosticsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    31, /* .membersSize */
    SubscriptionDiagnosticsDataType_members  /* .members */
},
/* ModelChangeStructureVerbMask */
{
    UA_TYPENAME("ModelChangeStructureVerbMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11941LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ModelChangeStructureVerbMask), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    ModelChangeStructureVerbMask_members  /* .members */
},
/* ModelChangeStructureDataType */
{
    UA_TYPENAME("ModelChangeStructureDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {877LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {879LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {878LU}}, /* .xmlEncodingId */
    sizeof(UA_ModelChangeStructureDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ModelChangeStructureDataType_members  /* .members */
},
/* SemanticChangeStructureDataType */
{
    UA_TYPENAME("SemanticChangeStructureDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {897LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {899LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {898LU}}, /* .xmlEncodingId */
    sizeof(UA_SemanticChangeStructureDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SemanticChangeStructureDataType_members  /* .members */
},
/* Range */
{
    UA_TYPENAME("Range") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {884LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {886LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {885LU}}, /* .xmlEncodingId */
    sizeof(UA_Range), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    Range_members  /* .members */
},
/* EUInformation */
{
    UA_TYPENAME("EUInformation") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {887LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {889LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {888LU}}, /* .xmlEncodingId */
    sizeof(UA_EUInformation), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    EUInformation_members  /* .members */
},
/* AxisScaleEnumeration */
{
    UA_TYPENAME("AxisScaleEnumeration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12077LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_AxisScaleEnumeration), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    AxisScaleEnumeration_members  /* .members */
},
/* ComplexNumberType */
{
    UA_TYPENAME("ComplexNumberType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12171LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12181LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12173LU}}, /* .xmlEncodingId */
    sizeof(UA_ComplexNumberType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ComplexNumberType_members  /* .members */
},
/* DoubleComplexNumberType */
{
    UA_TYPENAME("DoubleComplexNumberType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12172LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12182LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12174LU}}, /* .xmlEncodingId */
    sizeof(UA_DoubleComplexNumberType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DoubleComplexNumberType_members  /* .members */
},
/* AxisInformation */
{
    UA_TYPENAME("AxisInformation") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12079LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12089LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12081LU}}, /* .xmlEncodingId */
    sizeof(UA_AxisInformation), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    AxisInformation_members  /* .members */
},
/* XVType */
{
    UA_TYPENAME("XVType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12080LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12090LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {12082LU}}, /* .xmlEncodingId */
    sizeof(UA_XVType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    XVType_members  /* .members */
},
/* ProgramDiagnosticDataType */
{
    UA_TYPENAME("ProgramDiagnosticDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {894LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {896LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {895LU}}, /* .xmlEncodingId */
    sizeof(UA_ProgramDiagnosticDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    ProgramDiagnosticDataType_members  /* .members */
},
/* ProgramDiagnostic2DataType */
{
    UA_TYPENAME("ProgramDiagnostic2DataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24033LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {24034LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {24038LU}}, /* .xmlEncodingId */
    sizeof(UA_ProgramDiagnostic2DataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    12, /* .membersSize */
    ProgramDiagnostic2DataType_members  /* .members */
},
/* Annotation */
{
    UA_TYPENAME("Annotation") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {891LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {893LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {892LU}}, /* .xmlEncodingId */
    sizeof(UA_Annotation), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    Annotation_members  /* .members */
},
/* ExceptionDeviationFormat */
{
    UA_TYPENAME("ExceptionDeviationFormat") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {890LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ExceptionDeviationFormat), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    5, /* .membersSize */
    ExceptionDeviationFormat_members  /* .members */
},
/* EndpointType */
{
    UA_TYPENAME("EndpointType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15528LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15671LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15949LU}}, /* .xmlEncodingId */
    sizeof(UA_EndpointType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    EndpointType_members  /* .members */
},
/* StructureDescription */
{
    UA_TYPENAME("StructureDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15487LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {126LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15589LU}}, /* .xmlEncodingId */
    sizeof(UA_StructureDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    StructureDescription_members  /* .members */
},
/* FieldMetaData */
{
    UA_TYPENAME("FieldMetaData") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14524LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14839LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14795LU}}, /* .xmlEncodingId */
    sizeof(UA_FieldMetaData), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    FieldMetaData_members  /* .members */
},
/* PublishedEventsDataType */
{
    UA_TYPENAME("PublishedEventsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15582LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15681LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15954LU}}, /* .xmlEncodingId */
    sizeof(UA_PublishedEventsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    PublishedEventsDataType_members  /* .members */
},
/* PubSubGroupDataType */
{
    UA_TYPENAME("PubSubGroupDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15609LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15689LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15988LU}}, /* .xmlEncodingId */
    sizeof(UA_PubSubGroupDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    PubSubGroupDataType_members  /* .members */
},
/* WriterGroupDataType */
{
    UA_TYPENAME("WriterGroupDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15480LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {21150LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {21174LU}}, /* .xmlEncodingId */
    sizeof(UA_WriterGroupDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    16, /* .membersSize */
    WriterGroupDataType_members  /* .members */
},
/* FieldTargetDataType */
{
    UA_TYPENAME("FieldTargetDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14744LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14848LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14804LU}}, /* .xmlEncodingId */
    sizeof(UA_FieldTargetDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    FieldTargetDataType_members  /* .members */
},
/* SubscribedDataSetMirrorDataType */
{
    UA_TYPENAME("SubscribedDataSetMirrorDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15635LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15713LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16012LU}}, /* .xmlEncodingId */
    sizeof(UA_SubscribedDataSetMirrorDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SubscribedDataSetMirrorDataType_members  /* .members */
},
/* SecurityGroupDataType */
{
    UA_TYPENAME("SecurityGroupDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23601LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23853LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23921LU}}, /* .xmlEncodingId */
    sizeof(UA_SecurityGroupDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    SecurityGroupDataType_members  /* .members */
},
/* PubSubKeyPushTargetDataType */
{
    UA_TYPENAME("PubSubKeyPushTargetDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25270LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {25530LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {25546LU}}, /* .xmlEncodingId */
    sizeof(UA_PubSubKeyPushTargetDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    PubSubKeyPushTargetDataType_members  /* .members */
},
/* EnumDefinition */
{
    UA_TYPENAME("EnumDefinition") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {100LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {123LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14799LU}}, /* .xmlEncodingId */
    sizeof(UA_EnumDefinition), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    EnumDefinition_members  /* .members */
},
/* ReadEventDetails */
{
    UA_TYPENAME("ReadEventDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {644LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {646LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {645LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadEventDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ReadEventDetails_members  /* .members */
},
/* ReadProcessedDetails */
{
    UA_TYPENAME("ReadProcessedDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {650LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {652LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {651LU}}, /* .xmlEncodingId */
    sizeof(UA_ReadProcessedDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    ReadProcessedDetails_members  /* .members */
},
/* ModificationInfo */
{
    UA_TYPENAME("ModificationInfo") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11216LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {11226LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {11218LU}}, /* .xmlEncodingId */
    sizeof(UA_ModificationInfo), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ModificationInfo_members  /* .members */
},
/* HistoryModifiedData */
{
    UA_TYPENAME("HistoryModifiedData") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11217LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {11227LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {11219LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryModifiedData), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    HistoryModifiedData_members  /* .members */
},
/* HistoryEvent */
{
    UA_TYPENAME("HistoryEvent") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {659LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {661LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {660LU}}, /* .xmlEncodingId */
    sizeof(UA_HistoryEvent), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    HistoryEvent_members  /* .members */
},
/* UpdateEventDetails */
{
    UA_TYPENAME("UpdateEventDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {683LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {685LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {684LU}}, /* .xmlEncodingId */
    sizeof(UA_UpdateEventDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    UpdateEventDetails_members  /* .members */
},
/* DataChangeNotification */
{
    UA_TYPENAME("DataChangeNotification") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {809LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {811LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {810LU}}, /* .xmlEncodingId */
    sizeof(UA_DataChangeNotification), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DataChangeNotification_members  /* .members */
},
/* EventNotificationList */
{
    UA_TYPENAME("EventNotificationList") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {914LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {916LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {915LU}}, /* .xmlEncodingId */
    sizeof(UA_EventNotificationList), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    EventNotificationList_members  /* .members */
},
/* SessionDiagnosticsDataType */
{
    UA_TYPENAME("SessionDiagnosticsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {865LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {867LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {866LU}}, /* .xmlEncodingId */
    sizeof(UA_SessionDiagnosticsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    43, /* .membersSize */
    SessionDiagnosticsDataType_members  /* .members */
},
/* EnumDescription */
{
    UA_TYPENAME("EnumDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15488LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {127LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15590LU}}, /* .xmlEncodingId */
    sizeof(UA_EnumDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    EnumDescription_members  /* .members */
},
/* UABinaryFileDataType */
{
    UA_TYPENAME("UABinaryFileDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15006LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15422LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15531LU}}, /* .xmlEncodingId */
    sizeof(UA_UABinaryFileDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    UABinaryFileDataType_members  /* .members */
},
/* DataSetMetaDataType */
{
    UA_TYPENAME("DataSetMetaDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14523LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {124LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {14794LU}}, /* .xmlEncodingId */
    sizeof(UA_DataSetMetaDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    DataSetMetaDataType_members  /* .members */
},
/* PublishedDataSetDataType */
{
    UA_TYPENAME("PublishedDataSetDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15578LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15677LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15951LU}}, /* .xmlEncodingId */
    sizeof(UA_PublishedDataSetDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    PublishedDataSetDataType_members  /* .members */
},
/* DataSetReaderDataType */
{
    UA_TYPENAME("DataSetReaderDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15623LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15703LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16007LU}}, /* .xmlEncodingId */
    sizeof(UA_DataSetReaderDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    17, /* .membersSize */
    DataSetReaderDataType_members  /* .members */
},
/* TargetVariablesDataType */
{
    UA_TYPENAME("TargetVariablesDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15631LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15712LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {16011LU}}, /* .xmlEncodingId */
    sizeof(UA_TargetVariablesDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    TargetVariablesDataType_members  /* .members */
},
/* StandaloneSubscribedDataSetDataType */
{
    UA_TYPENAME("StandaloneSubscribedDataSetDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23600LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23852LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23920LU}}, /* .xmlEncodingId */
    sizeof(UA_StandaloneSubscribedDataSetDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    StandaloneSubscribedDataSetDataType_members  /* .members */
},
/* DataTypeSchemaHeader */
{
    UA_TYPENAME("DataTypeSchemaHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15534LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15676LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15950LU}}, /* .xmlEncodingId */
    sizeof(UA_DataTypeSchemaHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    DataTypeSchemaHeader_members  /* .members */
},
/* ReaderGroupDataType */
{
    UA_TYPENAME("ReaderGroupDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15520LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {21153LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {21177LU}}, /* .xmlEncodingId */
    sizeof(UA_ReaderGroupDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    ReaderGroupDataType_members  /* .members */
},
/* PubSubConnectionDataType */
{
    UA_TYPENAME("PubSubConnectionDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15617LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {15694LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {15992LU}}, /* .xmlEncodingId */
    sizeof(UA_PubSubConnectionDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    PubSubConnectionDataType_members  /* .members */
},
/* PubSubConfigurationDataType */
{
    UA_TYPENAME("PubSubConfigurationDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15530LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {21154LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {21178LU}}, /* .xmlEncodingId */
    sizeof(UA_PubSubConfigurationDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    PubSubConfigurationDataType_members  /* .members */
},
/* PubSubConfiguration2DataType */
{
    UA_TYPENAME("PubSubConfiguration2DataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23602LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {23854LU}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {23922LU}}, /* .xmlEncodingId */
    sizeof(UA_PubSubConfiguration2DataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    PubSubConfiguration2DataType_members  /* .members */
},
};


/**** amalgamated original file "1_build/src_generated/open62541/transport_generated.c" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/


/* MessageType */
static UA_DataTypeMember MessageType_members[8] = {
{
    UA_TYPENAME("ACK") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("HEL") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("MSG") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("OPN") /* .memberName */
    (const UA_DataType *)3, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("CLO") /* .memberName */
    (const UA_DataType *)4, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ERR") /* .memberName */
    (const UA_DataType *)5, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("RHE") /* .memberName */
    (const UA_DataType *)6, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("INVALID") /* .memberName */
    (const UA_DataType *)7, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* ChunkType */
static UA_DataTypeMember ChunkType_members[3] = {
{
    UA_TYPENAME("FINAL") /* .memberName */
    (const UA_DataType *)0, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("INTERMEDIATE") /* .memberName */
    (const UA_DataType *)1, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
},
{
    UA_TYPENAME("ABORT") /* .memberName */
    (const UA_DataType *)2, /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false /* .isOptional */
}};

/* TcpMessageHeader */
static UA_DataTypeMember TcpMessageHeader_members[2] = {
{
    UA_TYPENAME("MessageTypeAndChunkType") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpMessageHeader, messageSize) - offsetof(UA_TcpMessageHeader, messageTypeAndChunkType) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TcpHelloMessage */
static UA_DataTypeMember TcpHelloMessage_members[6] = {
{
    UA_TYPENAME("ProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiveBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, receiveBufferSize) - offsetof(UA_TcpHelloMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SendBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, sendBufferSize) - offsetof(UA_TcpHelloMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, maxMessageSize) - offsetof(UA_TcpHelloMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxChunkCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, maxChunkCount) - offsetof(UA_TcpHelloMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_TcpHelloMessage, endpointUrl) - offsetof(UA_TcpHelloMessage, maxChunkCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TcpReverseHelloMessage */
static UA_DataTypeMember TcpReverseHelloMessage_members[2] = {
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_TcpReverseHelloMessage, endpointUrl) - offsetof(UA_TcpReverseHelloMessage, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TcpAcknowledgeMessage */
static UA_DataTypeMember TcpAcknowledgeMessage_members[5] = {
{
    UA_TYPENAME("ProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiveBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - offsetof(UA_TcpAcknowledgeMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SendBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxChunkCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, maxChunkCount) - offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* TcpErrorMessage */
static UA_DataTypeMember TcpErrorMessage_members[2] = {
{
    UA_TYPENAME("Error") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Reason") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_TcpErrorMessage, reason) - offsetof(UA_TcpErrorMessage, error) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* AsymmetricAlgorithmSecurityHeader */
static UA_DataTypeMember AsymmetricAlgorithmSecurityHeader_members[3] = {
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SenderCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, securityPolicyUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiverCertificateThumbprint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_AsymmetricAlgorithmSecurityHeader, receiverCertificateThumbprint) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};

/* SequenceHeader */
static UA_DataTypeMember SequenceHeader_members[2] = {
{
    UA_TYPENAME("SequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SequenceHeader, requestId) - offsetof(UA_SequenceHeader, sequenceNumber) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
}};
UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT] = {
/* MessageType */
{
    UA_TYPENAME("MessageType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_MessageType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    8, /* .membersSize */
    MessageType_members  /* .members */
},
/* ChunkType */
{
    UA_TYPENAME("ChunkType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_ChunkType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    3, /* .membersSize */
    ChunkType_members  /* .members */
},
/* TcpMessageHeader */
{
    UA_TYPENAME("TcpMessageHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TcpMessageHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TcpMessageHeader_members  /* .members */
},
/* TcpHelloMessage */
{
    UA_TYPENAME("TcpHelloMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TcpHelloMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    TcpHelloMessage_members  /* .members */
},
/* TcpReverseHelloMessage */
{
    UA_TYPENAME("TcpReverseHelloMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TcpReverseHelloMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TcpReverseHelloMessage_members  /* .members */
},
/* TcpAcknowledgeMessage */
{
    UA_TYPENAME("TcpAcknowledgeMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TcpAcknowledgeMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    TcpAcknowledgeMessage_members  /* .members */
},
/* TcpErrorMessage */
{
    UA_TYPENAME("TcpErrorMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_TcpErrorMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TcpErrorMessage_members  /* .members */
},
/* AsymmetricAlgorithmSecurityHeader */
{
    UA_TYPENAME("AsymmetricAlgorithmSecurityHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_AsymmetricAlgorithmSecurityHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    AsymmetricAlgorithmSecurityHeader_members  /* .members */
},
/* SequenceHeader */
{
    UA_TYPENAME("SequenceHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .xmlEncodingId */
    sizeof(UA_SequenceHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SequenceHeader_members  /* .members */
},
};


/**** amalgamated original file "1_build/src_generated/open62541/statuscodes.c" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/


typedef struct {
    UA_StatusCode code;
    const char *name;
} UA_StatusCodeName;

#ifndef UA_ENABLE_STATUSCODE_DESCRIPTIONS
static const char * emptyStatusCodeName = "";
const char * UA_StatusCode_name(UA_StatusCode code) {
    return emptyStatusCodeName;
}
#else
static const size_t statusCodeDescriptionsSize = 253;
static const UA_StatusCodeName statusCodeDescriptions[253] = {
    {UA_STATUSCODE_GOOD, "Good"},
    {UA_STATUSCODE_GOOD, "Good"},
    {UA_STATUSCODE_UNCERTAIN, "Uncertain"},
    {UA_STATUSCODE_BAD, "Bad"},
    {UA_STATUSCODE_BADUNEXPECTEDERROR, "BadUnexpectedError"},
    {UA_STATUSCODE_BADINTERNALERROR, "BadInternalError"},
    {UA_STATUSCODE_BADOUTOFMEMORY, "BadOutOfMemory"},
    {UA_STATUSCODE_BADRESOURCEUNAVAILABLE, "BadResourceUnavailable"},
    {UA_STATUSCODE_BADCOMMUNICATIONERROR, "BadCommunicationError"},
    {UA_STATUSCODE_BADENCODINGERROR, "BadEncodingError"},
    {UA_STATUSCODE_BADDECODINGERROR, "BadDecodingError"},
    {UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED, "BadEncodingLimitsExceeded"},
    {UA_STATUSCODE_BADREQUESTTOOLARGE, "BadRequestTooLarge"},
    {UA_STATUSCODE_BADRESPONSETOOLARGE, "BadResponseTooLarge"},
    {UA_STATUSCODE_BADUNKNOWNRESPONSE, "BadUnknownResponse"},
    {UA_STATUSCODE_BADTIMEOUT, "BadTimeout"},
    {UA_STATUSCODE_BADSERVICEUNSUPPORTED, "BadServiceUnsupported"},
    {UA_STATUSCODE_BADSHUTDOWN, "BadShutdown"},
    {UA_STATUSCODE_BADSERVERNOTCONNECTED, "BadServerNotConnected"},
    {UA_STATUSCODE_BADSERVERHALTED, "BadServerHalted"},
    {UA_STATUSCODE_BADNOTHINGTODO, "BadNothingToDo"},
    {UA_STATUSCODE_BADTOOMANYOPERATIONS, "BadTooManyOperations"},
    {UA_STATUSCODE_BADTOOMANYMONITOREDITEMS, "BadTooManyMonitoredItems"},
    {UA_STATUSCODE_BADDATATYPEIDUNKNOWN, "BadDataTypeIdUnknown"},
    {UA_STATUSCODE_BADCERTIFICATEINVALID, "BadCertificateInvalid"},
    {UA_STATUSCODE_BADSECURITYCHECKSFAILED, "BadSecurityChecksFailed"},
    {UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED, "BadCertificatePolicyCheckFailed"},
    {UA_STATUSCODE_BADCERTIFICATETIMEINVALID, "BadCertificateTimeInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID, "BadCertificateIssuerTimeInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID, "BadCertificateHostNameInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEURIINVALID, "BadCertificateUriInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED, "BadCertificateUseNotAllowed"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED, "BadCertificateIssuerUseNotAllowed"},
    {UA_STATUSCODE_BADCERTIFICATEUNTRUSTED, "BadCertificateUntrusted"},
    {UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN, "BadCertificateRevocationUnknown"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN, "BadCertificateIssuerRevocationUnknown"},
    {UA_STATUSCODE_BADCERTIFICATEREVOKED, "BadCertificateRevoked"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED, "BadCertificateIssuerRevoked"},
    {UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE, "BadCertificateChainIncomplete"},
    {UA_STATUSCODE_BADUSERACCESSDENIED, "BadUserAccessDenied"},
    {UA_STATUSCODE_BADIDENTITYTOKENINVALID, "BadIdentityTokenInvalid"},
    {UA_STATUSCODE_BADIDENTITYTOKENREJECTED, "BadIdentityTokenRejected"},
    {UA_STATUSCODE_BADSECURECHANNELIDINVALID, "BadSecureChannelIdInvalid"},
    {UA_STATUSCODE_BADINVALIDTIMESTAMP, "BadInvalidTimestamp"},
    {UA_STATUSCODE_BADNONCEINVALID, "BadNonceInvalid"},
    {UA_STATUSCODE_BADSESSIONIDINVALID, "BadSessionIdInvalid"},
    {UA_STATUSCODE_BADSESSIONCLOSED, "BadSessionClosed"},
    {UA_STATUSCODE_BADSESSIONNOTACTIVATED, "BadSessionNotActivated"},
    {UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID, "BadSubscriptionIdInvalid"},
    {UA_STATUSCODE_BADREQUESTHEADERINVALID, "BadRequestHeaderInvalid"},
    {UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID, "BadTimestampsToReturnInvalid"},
    {UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT, "BadRequestCancelledByClient"},
    {UA_STATUSCODE_BADTOOMANYARGUMENTS, "BadTooManyArguments"},
    {UA_STATUSCODE_BADLICENSEEXPIRED, "BadLicenseExpired"},
    {UA_STATUSCODE_BADLICENSELIMITSEXCEEDED, "BadLicenseLimitsExceeded"},
    {UA_STATUSCODE_BADLICENSENOTAVAILABLE, "BadLicenseNotAvailable"},
    {UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED, "GoodSubscriptionTransferred"},
    {UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY, "GoodCompletesAsynchronously"},
    {UA_STATUSCODE_GOODOVERLOAD, "GoodOverload"},
    {UA_STATUSCODE_GOODCLAMPED, "GoodClamped"},
    {UA_STATUSCODE_BADNOCOMMUNICATION, "BadNoCommunication"},
    {UA_STATUSCODE_BADWAITINGFORINITIALDATA, "BadWaitingForInitialData"},
    {UA_STATUSCODE_BADNODEIDINVALID, "BadNodeIdInvalid"},
    {UA_STATUSCODE_BADNODEIDUNKNOWN, "BadNodeIdUnknown"},
    {UA_STATUSCODE_BADATTRIBUTEIDINVALID, "BadAttributeIdInvalid"},
    {UA_STATUSCODE_BADINDEXRANGEINVALID, "BadIndexRangeInvalid"},
    {UA_STATUSCODE_BADINDEXRANGENODATA, "BadIndexRangeNoData"},
    {UA_STATUSCODE_BADDATAENCODINGINVALID, "BadDataEncodingInvalid"},
    {UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED, "BadDataEncodingUnsupported"},
    {UA_STATUSCODE_BADNOTREADABLE, "BadNotReadable"},
    {UA_STATUSCODE_BADNOTWRITABLE, "BadNotWritable"},
    {UA_STATUSCODE_BADOUTOFRANGE, "BadOutOfRange"},
    {UA_STATUSCODE_BADNOTSUPPORTED, "BadNotSupported"},
    {UA_STATUSCODE_BADNOTFOUND, "BadNotFound"},
    {UA_STATUSCODE_BADOBJECTDELETED, "BadObjectDeleted"},
    {UA_STATUSCODE_BADNOTIMPLEMENTED, "BadNotImplemented"},
    {UA_STATUSCODE_BADMONITORINGMODEINVALID, "BadMonitoringModeInvalid"},
    {UA_STATUSCODE_BADMONITOREDITEMIDINVALID, "BadMonitoredItemIdInvalid"},
    {UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID, "BadMonitoredItemFilterInvalid"},
    {UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED, "BadMonitoredItemFilterUnsupported"},
    {UA_STATUSCODE_BADFILTERNOTALLOWED, "BadFilterNotAllowed"},
    {UA_STATUSCODE_BADSTRUCTUREMISSING, "BadStructureMissing"},
    {UA_STATUSCODE_BADEVENTFILTERINVALID, "BadEventFilterInvalid"},
    {UA_STATUSCODE_BADCONTENTFILTERINVALID, "BadContentFilterInvalid"},
    {UA_STATUSCODE_BADFILTEROPERATORINVALID, "BadFilterOperatorInvalid"},
    {UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED, "BadFilterOperatorUnsupported"},
    {UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH, "BadFilterOperandCountMismatch"},
    {UA_STATUSCODE_BADFILTEROPERANDINVALID, "BadFilterOperandInvalid"},
    {UA_STATUSCODE_BADFILTERELEMENTINVALID, "BadFilterElementInvalid"},
    {UA_STATUSCODE_BADFILTERLITERALINVALID, "BadFilterLiteralInvalid"},
    {UA_STATUSCODE_BADCONTINUATIONPOINTINVALID, "BadContinuationPointInvalid"},
    {UA_STATUSCODE_BADNOCONTINUATIONPOINTS, "BadNoContinuationPoints"},
    {UA_STATUSCODE_BADREFERENCETYPEIDINVALID, "BadReferenceTypeIdInvalid"},
    {UA_STATUSCODE_BADBROWSEDIRECTIONINVALID, "BadBrowseDirectionInvalid"},
    {UA_STATUSCODE_BADNODENOTINVIEW, "BadNodeNotInView"},
    {UA_STATUSCODE_BADNUMERICOVERFLOW, "BadNumericOverflow"},
    {UA_STATUSCODE_BADSERVERURIINVALID, "BadServerUriInvalid"},
    {UA_STATUSCODE_BADSERVERNAMEMISSING, "BadServerNameMissing"},
    {UA_STATUSCODE_BADDISCOVERYURLMISSING, "BadDiscoveryUrlMissing"},
    {UA_STATUSCODE_BADSEMAPHOREFILEMISSING, "BadSemaphoreFileMissing"},
    {UA_STATUSCODE_BADREQUESTTYPEINVALID, "BadRequestTypeInvalid"},
    {UA_STATUSCODE_BADSECURITYMODEREJECTED, "BadSecurityModeRejected"},
    {UA_STATUSCODE_BADSECURITYPOLICYREJECTED, "BadSecurityPolicyRejected"},
    {UA_STATUSCODE_BADTOOMANYSESSIONS, "BadTooManySessions"},
    {UA_STATUSCODE_BADUSERSIGNATUREINVALID, "BadUserSignatureInvalid"},
    {UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID, "BadApplicationSignatureInvalid"},
    {UA_STATUSCODE_BADNOVALIDCERTIFICATES, "BadNoValidCertificates"},
    {UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED, "BadIdentityChangeNotSupported"},
    {UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST, "BadRequestCancelledByRequest"},
    {UA_STATUSCODE_BADPARENTNODEIDINVALID, "BadParentNodeIdInvalid"},
    {UA_STATUSCODE_BADREFERENCENOTALLOWED, "BadReferenceNotAllowed"},
    {UA_STATUSCODE_BADNODEIDREJECTED, "BadNodeIdRejected"},
    {UA_STATUSCODE_BADNODEIDEXISTS, "BadNodeIdExists"},
    {UA_STATUSCODE_BADNODECLASSINVALID, "BadNodeClassInvalid"},
    {UA_STATUSCODE_BADBROWSENAMEINVALID, "BadBrowseNameInvalid"},
    {UA_STATUSCODE_BADBROWSENAMEDUPLICATED, "BadBrowseNameDuplicated"},
    {UA_STATUSCODE_BADNODEATTRIBUTESINVALID, "BadNodeAttributesInvalid"},
    {UA_STATUSCODE_BADTYPEDEFINITIONINVALID, "BadTypeDefinitionInvalid"},
    {UA_STATUSCODE_BADSOURCENODEIDINVALID, "BadSourceNodeIdInvalid"},
    {UA_STATUSCODE_BADTARGETNODEIDINVALID, "BadTargetNodeIdInvalid"},
    {UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED, "BadDuplicateReferenceNotAllowed"},
    {UA_STATUSCODE_BADINVALIDSELFREFERENCE, "BadInvalidSelfReference"},
    {UA_STATUSCODE_BADREFERENCELOCALONLY, "BadReferenceLocalOnly"},
    {UA_STATUSCODE_BADNODELETERIGHTS, "BadNoDeleteRights"},
    {UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED, "UncertainReferenceNotDeleted"},
    {UA_STATUSCODE_BADSERVERINDEXINVALID, "BadServerIndexInvalid"},
    {UA_STATUSCODE_BADVIEWIDUNKNOWN, "BadViewIdUnknown"},
    {UA_STATUSCODE_BADVIEWTIMESTAMPINVALID, "BadViewTimestampInvalid"},
    {UA_STATUSCODE_BADVIEWPARAMETERMISMATCH, "BadViewParameterMismatch"},
    {UA_STATUSCODE_BADVIEWVERSIONINVALID, "BadViewVersionInvalid"},
    {UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE, "UncertainNotAllNodesAvailable"},
    {UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE, "GoodResultsMayBeIncomplete"},
    {UA_STATUSCODE_BADNOTTYPEDEFINITION, "BadNotTypeDefinition"},
    {UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER, "UncertainReferenceOutOfServer"},
    {UA_STATUSCODE_BADTOOMANYMATCHES, "BadTooManyMatches"},
    {UA_STATUSCODE_BADQUERYTOOCOMPLEX, "BadQueryTooComplex"},
    {UA_STATUSCODE_BADNOMATCH, "BadNoMatch"},
    {UA_STATUSCODE_BADMAXAGEINVALID, "BadMaxAgeInvalid"},
    {UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT, "BadSecurityModeInsufficient"},
    {UA_STATUSCODE_BADHISTORYOPERATIONINVALID, "BadHistoryOperationInvalid"},
    {UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED, "BadHistoryOperationUnsupported"},
    {UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT, "BadInvalidTimestampArgument"},
    {UA_STATUSCODE_BADWRITENOTSUPPORTED, "BadWriteNotSupported"},
    {UA_STATUSCODE_BADTYPEMISMATCH, "BadTypeMismatch"},
    {UA_STATUSCODE_BADMETHODINVALID, "BadMethodInvalid"},
    {UA_STATUSCODE_BADARGUMENTSMISSING, "BadArgumentsMissing"},
    {UA_STATUSCODE_BADNOTEXECUTABLE, "BadNotExecutable"},
    {UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS, "BadTooManySubscriptions"},
    {UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS, "BadTooManyPublishRequests"},
    {UA_STATUSCODE_BADNOSUBSCRIPTION, "BadNoSubscription"},
    {UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN, "BadSequenceNumberUnknown"},
    {UA_STATUSCODE_GOODRETRANSMISSIONQUEUENOTSUPPORTED, "GoodRetransmissionQueueNotSupported"},
    {UA_STATUSCODE_BADMESSAGENOTAVAILABLE, "BadMessageNotAvailable"},
    {UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE, "BadInsufficientClientProfile"},
    {UA_STATUSCODE_BADSTATENOTACTIVE, "BadStateNotActive"},
    {UA_STATUSCODE_BADALREADYEXISTS, "BadAlreadyExists"},
    {UA_STATUSCODE_BADTCPSERVERTOOBUSY, "BadTcpServerTooBusy"},
    {UA_STATUSCODE_BADTCPMESSAGETYPEINVALID, "BadTcpMessageTypeInvalid"},
    {UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN, "BadTcpSecureChannelUnknown"},
    {UA_STATUSCODE_BADTCPMESSAGETOOLARGE, "BadTcpMessageTooLarge"},
    {UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES, "BadTcpNotEnoughResources"},
    {UA_STATUSCODE_BADTCPINTERNALERROR, "BadTcpInternalError"},
    {UA_STATUSCODE_BADTCPENDPOINTURLINVALID, "BadTcpEndpointUrlInvalid"},
    {UA_STATUSCODE_BADREQUESTINTERRUPTED, "BadRequestInterrupted"},
    {UA_STATUSCODE_BADREQUESTTIMEOUT, "BadRequestTimeout"},
    {UA_STATUSCODE_BADSECURECHANNELCLOSED, "BadSecureChannelClosed"},
    {UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN, "BadSecureChannelTokenUnknown"},
    {UA_STATUSCODE_BADSEQUENCENUMBERINVALID, "BadSequenceNumberInvalid"},
    {UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED, "BadProtocolVersionUnsupported"},
    {UA_STATUSCODE_BADCONFIGURATIONERROR, "BadConfigurationError"},
    {UA_STATUSCODE_BADNOTCONNECTED, "BadNotConnected"},
    {UA_STATUSCODE_BADDEVICEFAILURE, "BadDeviceFailure"},
    {UA_STATUSCODE_BADSENSORFAILURE, "BadSensorFailure"},
    {UA_STATUSCODE_BADOUTOFSERVICE, "BadOutOfService"},
    {UA_STATUSCODE_BADDEADBANDFILTERINVALID, "BadDeadbandFilterInvalid"},
    {UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE, "UncertainNoCommunicationLastUsableValue"},
    {UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE, "UncertainLastUsableValue"},
    {UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE, "UncertainSubstituteValue"},
    {UA_STATUSCODE_UNCERTAININITIALVALUE, "UncertainInitialValue"},
    {UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE, "UncertainSensorNotAccurate"},
    {UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED, "UncertainEngineeringUnitsExceeded"},
    {UA_STATUSCODE_UNCERTAINSUBNORMAL, "UncertainSubNormal"},
    {UA_STATUSCODE_GOODLOCALOVERRIDE, "GoodLocalOverride"},
    {UA_STATUSCODE_BADREFRESHINPROGRESS, "BadRefreshInProgress"},
    {UA_STATUSCODE_BADCONDITIONALREADYDISABLED, "BadConditionAlreadyDisabled"},
    {UA_STATUSCODE_BADCONDITIONALREADYENABLED, "BadConditionAlreadyEnabled"},
    {UA_STATUSCODE_BADCONDITIONDISABLED, "BadConditionDisabled"},
    {UA_STATUSCODE_BADEVENTIDUNKNOWN, "BadEventIdUnknown"},
    {UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE, "BadEventNotAcknowledgeable"},
    {UA_STATUSCODE_BADDIALOGNOTACTIVE, "BadDialogNotActive"},
    {UA_STATUSCODE_BADDIALOGRESPONSEINVALID, "BadDialogResponseInvalid"},
    {UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED, "BadConditionBranchAlreadyAcked"},
    {UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED, "BadConditionBranchAlreadyConfirmed"},
    {UA_STATUSCODE_BADCONDITIONALREADYSHELVED, "BadConditionAlreadyShelved"},
    {UA_STATUSCODE_BADCONDITIONNOTSHELVED, "BadConditionNotShelved"},
    {UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE, "BadShelvingTimeOutOfRange"},
    {UA_STATUSCODE_BADNODATA, "BadNoData"},
    {UA_STATUSCODE_BADBOUNDNOTFOUND, "BadBoundNotFound"},
    {UA_STATUSCODE_BADBOUNDNOTSUPPORTED, "BadBoundNotSupported"},
    {UA_STATUSCODE_BADDATALOST, "BadDataLost"},
    {UA_STATUSCODE_BADDATAUNAVAILABLE, "BadDataUnavailable"},
    {UA_STATUSCODE_BADENTRYEXISTS, "BadEntryExists"},
    {UA_STATUSCODE_BADNOENTRYEXISTS, "BadNoEntryExists"},
    {UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED, "BadTimestampNotSupported"},
    {UA_STATUSCODE_GOODENTRYINSERTED, "GoodEntryInserted"},
    {UA_STATUSCODE_GOODENTRYREPLACED, "GoodEntryReplaced"},
    {UA_STATUSCODE_UNCERTAINDATASUBNORMAL, "UncertainDataSubNormal"},
    {UA_STATUSCODE_GOODNODATA, "GoodNoData"},
    {UA_STATUSCODE_GOODMOREDATA, "GoodMoreData"},
    {UA_STATUSCODE_BADAGGREGATELISTMISMATCH, "BadAggregateListMismatch"},
    {UA_STATUSCODE_BADAGGREGATENOTSUPPORTED, "BadAggregateNotSupported"},
    {UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS, "BadAggregateInvalidInputs"},
    {UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED, "BadAggregateConfigurationRejected"},
    {UA_STATUSCODE_GOODDATAIGNORED, "GoodDataIgnored"},
    {UA_STATUSCODE_BADREQUESTNOTALLOWED, "BadRequestNotAllowed"},
    {UA_STATUSCODE_BADREQUESTNOTCOMPLETE, "BadRequestNotComplete"},
    {UA_STATUSCODE_BADTRANSACTIONPENDING, "BadTransactionPending"},
    {UA_STATUSCODE_BADTICKETREQUIRED, "BadTicketRequired"},
    {UA_STATUSCODE_BADTICKETINVALID, "BadTicketInvalid"},
    {UA_STATUSCODE_GOODEDITED, "GoodEdited"},
    {UA_STATUSCODE_GOODPOSTACTIONFAILED, "GoodPostActionFailed"},
    {UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED, "UncertainDominantValueChanged"},
    {UA_STATUSCODE_GOODDEPENDENTVALUECHANGED, "GoodDependentValueChanged"},
    {UA_STATUSCODE_BADDOMINANTVALUECHANGED, "BadDominantValueChanged"},
    {UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED, "UncertainDependentValueChanged"},
    {UA_STATUSCODE_BADDEPENDENTVALUECHANGED, "BadDependentValueChanged"},
    {UA_STATUSCODE_GOODEDITED_DEPENDENTVALUECHANGED, "GoodEdited_DependentValueChanged"},
    {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED, "GoodEdited_DominantValueChanged"},
    {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "GoodEdited_DominantValueChanged_DependentValueChanged"},
    {UA_STATUSCODE_BADEDITED_OUTOFRANGE, "BadEdited_OutOfRange"},
    {UA_STATUSCODE_BADINITIALVALUE_OUTOFRANGE, "BadInitialValue_OutOfRange"},
    {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED, "BadOutOfRange_DominantValueChanged"},
    {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged"},
    {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadOutOfRange_DominantValueChanged_DependentValueChanged"},
    {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged_DependentValueChanged"},
    {UA_STATUSCODE_GOODCOMMUNICATIONEVENT, "GoodCommunicationEvent"},
    {UA_STATUSCODE_GOODSHUTDOWNEVENT, "GoodShutdownEvent"},
    {UA_STATUSCODE_GOODCALLAGAIN, "GoodCallAgain"},
    {UA_STATUSCODE_GOODNONCRITICALTIMEOUT, "GoodNonCriticalTimeout"},
    {UA_STATUSCODE_BADINVALIDARGUMENT, "BadInvalidArgument"},
    {UA_STATUSCODE_BADCONNECTIONREJECTED, "BadConnectionRejected"},
    {UA_STATUSCODE_BADDISCONNECT, "BadDisconnect"},
    {UA_STATUSCODE_BADCONNECTIONCLOSED, "BadConnectionClosed"},
    {UA_STATUSCODE_BADINVALIDSTATE, "BadInvalidState"},
    {UA_STATUSCODE_BADENDOFSTREAM, "BadEndOfStream"},
    {UA_STATUSCODE_BADNODATAAVAILABLE, "BadNoDataAvailable"},
    {UA_STATUSCODE_BADWAITINGFORRESPONSE, "BadWaitingForResponse"},
    {UA_STATUSCODE_BADOPERATIONABANDONED, "BadOperationAbandoned"},
    {UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK, "BadExpectedStreamToBlock"},
    {UA_STATUSCODE_BADWOULDBLOCK, "BadWouldBlock"},
    {UA_STATUSCODE_BADSYNTAXERROR, "BadSyntaxError"},
    {UA_STATUSCODE_BADMAXCONNECTIONSREACHED, "BadMaxConnectionsReached"},
    {0xffffffff, "Unknown StatusCode"}
};

const char * UA_StatusCode_name(UA_StatusCode code) {
    for (size_t i = 0; i < statusCodeDescriptionsSize; ++i) {
        if (UA_StatusCode_isEqualTop(statusCodeDescriptions[i].code,code))
            return statusCodeDescriptions[i].name;
    }
    return statusCodeDescriptions[statusCodeDescriptionsSize-1].name;
}

#endif

/**** amalgamated original file "/src/util/ua_util.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014, 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */

/* If UA_ENABLE_INLINABLE_EXPORT is enabled, then this file is the compilation
 * unit for the generated code from UA_INLINABLE definitions. */
#define UA_INLINABLE_IMPL 1

// Not used in this translation unit, but exposes symbols that are used in other translation units


#if defined(UA_ARCHITECTURE_WIN32)
#include <wtypes.h>
#include <winbase.h>
#endif


char *securityModeNames[4] = {"Invalid", "None", "Sign", "SignAndEncrypt"};

static const char * attributeIdNames[28] = {
    "Invalid", "NodeId", "NodeClass", "BrowseName", "DisplayName", "Description",
    "WriteMask", "UserWriteMask", "IsAbstract", "Symmetric", "InverseName",
    "ContainsNoLoops", "EventNotifier", "Value", "DataType", "ValueRank",
    "ArrayDimensions", "AccessLevel", "UserAccessLevel", "MinimumSamplingInterval",
    "Historizing", "Executable", "UserExecutable", "DataTypeDefinition",
    "RolePermissions", "UserRolePermissions", "AccessRestrictions", "AccessLevelEx"
};

const char *
UA_AttributeId_name(UA_AttributeId attrId) {
    if(attrId < 0 || attrId > UA_ATTRIBUTEID_ACCESSLEVELEX)
        return attributeIdNames[0];
    return attributeIdNames[attrId];
}

/* OR-ing 32 goes from upper-case to lower-case */
UA_AttributeId
UA_AttributeId_fromName(const UA_String name) {
    for(size_t i = 0; i < 28; i++) {
        if(strlen(attributeIdNames[i]) != name.length)
            continue;
        for(size_t j = 0; j < name.length; j++) {
            if((attributeIdNames[i][j] | 32) != (name.data[j] | 32))
                goto next;
        }
        return (UA_AttributeId)i;
    next:
        continue;
    }
    return UA_ATTRIBUTEID_INVALID;
}

static UA_DataTypeKind
typeEquivalence(const UA_DataType *t) {
    UA_DataTypeKind k = (UA_DataTypeKind)t->typeKind;
    if(k == UA_DATATYPEKIND_ENUM)
        return UA_DATATYPEKIND_INT32;
    return k;
}

void
adjustType(UA_Variant *value, const UA_DataType *targetType) {
    /* If the value is empty, there is nothing we can do here */
    const UA_DataType *type = value->type;
    if(!type || !targetType)
        return;

    /* A string is written to a byte array. the valuerank and array dimensions
     * are checked later */
    if(targetType == &UA_TYPES[UA_TYPES_BYTE] &&
       type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
       UA_Variant_isScalar(value)) {
        UA_ByteString *str = (UA_ByteString*)value->data;
        value->type = &UA_TYPES[UA_TYPES_BYTE];
        value->arrayLength = str->length;
        value->data = str->data;
        return;
    }

    /* An enum was sent as an int32, or an opaque type as a bytestring. This
     * is detected with the typeKind indicating the "true" datatype. */
    UA_DataTypeKind te1 = typeEquivalence(targetType);
    UA_DataTypeKind te2 = typeEquivalence(type);
    if(te1 == te2 && te1 <= UA_DATATYPEKIND_ENUM) {
        value->type = targetType;
        return;
    }

    /* Add more possible type adjustments here. What are they? */
}

size_t
UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, UA_UInt32 *number, UA_Byte base) {
    UA_assert(buf);
    UA_assert(number);
    u32 n = 0;
    size_t progress = 0;
    /* read numbers until the end or a non-number character appears */
    while(progress < buflen) {
        u8 c = buf[progress];
        if(c >= '0' && c <= '9' && c <= '0' + (base-1))
           n = (n * base) + c - '0';
        else if(base > 9 && c >= 'a' && c <= 'z' && c <= 'a' + (base-11))
           n = (n * base) + c-'a' + 10;
        else if(base > 9 && c >= 'A' && c <= 'Z' && c <= 'A' + (base-11))
           n = (n * base) + c-'A' + 10;
        else
           break;
        ++progress;
    }
    *number = n;
    return progress;
}

size_t
UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number) {
    return UA_readNumberWithBase(buf, buflen, number, 10);
}

#define UA_SCHEMAS_SIZE 4
#define UA_ETH_SCHEMA_INDEX 2

static const char* schemas[UA_SCHEMAS_SIZE] = {
    "opc.tcp://", "opc.udp://", "opc.eth://", "opc.mqtt://"
};

UA_StatusCode
UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
                    UA_UInt16 *outPort, UA_String *outPath) {
    /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */
    if(endpointUrl->length < 11) {
        return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
    }

    /* Which type of schema is this? */
    unsigned schemaType = 0;
    for(; schemaType < UA_SCHEMAS_SIZE; schemaType++) {
        if(strncmp((char*)endpointUrl->data,
                   schemas[schemaType],
                   strlen(schemas[schemaType])) == 0)
            break;
    }
    if(schemaType == UA_SCHEMAS_SIZE)
        return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;

    /* Forward the current position until the first colon or slash */
    size_t start = strlen(schemas[schemaType]);
    size_t curr = start;
    UA_Boolean ipv6 = false;
    if(endpointUrl->length > curr && endpointUrl->data[curr] == '[') {
        /* IPv6: opc.tcp://[2001:0db8:85a3::8a2e:0370:7334]:1234/path */
        for(; curr < endpointUrl->length; ++curr) {
            if(endpointUrl->data[curr] == ']')
                break;
        }
        if(curr == endpointUrl->length)
            return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
        curr++;
        ipv6 = true;
    } else {
        /* IPv4 or hostname: opc.tcp://something.something:1234/path */
        for(; curr < endpointUrl->length; ++curr) {
            if(endpointUrl->data[curr] == ':' || endpointUrl->data[curr] == '/')
                break;
        }
    }

    /* Set the hostname */
    if(ipv6) {
        /* Skip the ipv6 '[]' container for getaddrinfo() later */
        outHostname->data = &endpointUrl->data[start+1];
        outHostname->length = curr - (start+2);
    } else {
        outHostname->data = &endpointUrl->data[start];
        outHostname->length = curr - start;
    }

    /* Empty string? */
    if(outHostname->length == 0)
        outHostname->data = NULL;

    /* Already at the end */
    if(curr == endpointUrl->length)
        return UA_STATUSCODE_GOOD;

    /* Set the port - and for ETH set the VID.PCP postfix in the outpath string.
     * We have to parse that externally. */
    if(endpointUrl->data[curr] == ':') {
        if(++curr == endpointUrl->length)
            return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;

        /* ETH schema */
        if(schemaType == UA_ETH_SCHEMA_INDEX) {
            if(outPath != NULL) {
                outPath->data = &endpointUrl->data[curr];
                outPath->length = endpointUrl->length - curr;
            }
            return UA_STATUSCODE_GOOD;
        }

        u32 largeNum;
        size_t progress = UA_readNumber(&endpointUrl->data[curr],
                                        endpointUrl->length - curr, &largeNum);
        if(progress == 0 || largeNum > 65535)
            return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
        /* Test if the end of a valid port was reached */
        curr += progress;
        if(curr == endpointUrl->length || endpointUrl->data[curr] == '/')
            *outPort = (u16)largeNum;
        if(curr == endpointUrl->length)
            return UA_STATUSCODE_GOOD;
    }

    /* Set the path */
    UA_assert(curr < endpointUrl->length);
    if(endpointUrl->data[curr] != '/')
        return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
    if(++curr == endpointUrl->length)
        return UA_STATUSCODE_GOOD;
    if(outPath != NULL) {
        outPath->data = &endpointUrl->data[curr];
        outPath->length = endpointUrl->length - curr;

        /* Remove trailing slash from the path */
        if(endpointUrl->data[endpointUrl->length - 1] == '/')
            outPath->length--;

        /* Empty string? */
        if(outPath->length == 0)
            outPath->data = NULL;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target,
                            UA_UInt16 *vid, UA_Byte *pcp) {
    /* Url must begin with "opc.eth://" */
    if(endpointUrl->length < 11) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(strncmp((char*) endpointUrl->data, "opc.eth://", 10) != 0) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Where does the host address end? */
    size_t curr = 10;
    for(; curr < endpointUrl->length; ++curr) {
        if(endpointUrl->data[curr] == ':') {
           break;
        }
    }

    /* set host address */
    target->data = &endpointUrl->data[10];
    target->length = curr - 10;
    if(curr == endpointUrl->length) {
        return UA_STATUSCODE_GOOD;
    }

    /* Set VLAN */
    u32 value = 0;
    curr++;  /* skip ':' */
    size_t progress = UA_readNumber(&endpointUrl->data[curr],
                                    endpointUrl->length - curr, &value);
    if(progress == 0 || value > 4096) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    curr += progress;
    if(curr == endpointUrl->length || endpointUrl->data[curr] == '.') {
        *vid = (UA_UInt16) value;
    }
    if(curr == endpointUrl->length) {
        return UA_STATUSCODE_GOOD;
    }

    /* Set priority */
    if(endpointUrl->data[curr] != '.') {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    curr++;  /* skip '.' */
    progress = UA_readNumber(&endpointUrl->data[curr],
                             endpointUrl->length - curr, &value);
    if(progress == 0 || value > 7) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    curr += progress;
    if(curr != endpointUrl->length) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    *pcp = (UA_Byte) value;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ByteString_toBase64(const UA_ByteString *byteString,
                       UA_String *str) {
    UA_String_init(str);
    if(!byteString || !byteString->data || byteString->length == 0)
        return UA_STATUSCODE_GOOD;

    str->data = (UA_Byte*)
        UA_base64(byteString->data, byteString->length, &str->length);
    if(!str->data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ByteString_fromBase64(UA_ByteString *bs,
                         const UA_String *input) {
    UA_ByteString_init(bs);
    if(input->length == 0)
        return UA_STATUSCODE_GOOD;
    bs->data = UA_unbase64((const unsigned char*)input->data,
                           input->length, &bs->length);
    /* TODO: Differentiate between encoding and memory errors */
    if(!bs->data)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static u8
printNum(i32 n, char *pos, u8 min_digits) {
    char digits[10];
    u8 len = 0;
    /* Handle negative values */
    if(n < 0) {
        pos[len++] = '-';
        n = -n;
    }

    /* Extract the digits */
    u8 i = 0;
    for(; i < min_digits || n > 0; i++) {
        digits[i] = (char)((n % 10) + '0');
        n /= 10;
    }

    /* Print in reverse order and return */
    for(; i > 0; i--)
        pos[len++] = digits[i-1];
    return len;
}

#define UA_DATETIME_LENGTH 40

UA_StatusCode
encodeDateTime(const UA_DateTime dt, UA_String *output) {
    char buffer[UA_DATETIME_LENGTH];
    char *pos = buffer;

    if(output->length > 0) {
        if(output->length < UA_DATETIME_LENGTH)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        pos = (char*)output->data;
    }

    /* Format: -yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z' is used. max 31 bytes.
     * Note the optional minus for negative years. */
    UA_DateTimeStruct tSt = UA_DateTime_toStruct(dt);
    pos += printNum(tSt.year, pos, 4);
    *(pos++) = '-';
    pos += printNum(tSt.month, pos, 2);
    *(pos++) = '-';
    pos += printNum(tSt.day, pos, 2);
    *(pos++) = 'T';
    pos += printNum(tSt.hour, pos, 2);
    *(pos++) = ':';
    pos += printNum(tSt.min, pos, 2);
    *(pos++) = ':';
    pos += printNum(tSt.sec, pos, 2);
    *(pos++) = '.';
    pos += printNum(tSt.milliSec, pos, 3);
    pos += printNum(tSt.microSec, pos, 3);
    pos += printNum(tSt.nanoSec, pos, 3);

    /* Remove trailing zeros */
    pos--;
    while(*pos == '0')
        pos--;
    if(*pos == '.')
        pos--;

    pos++;
    *(pos++) = 'Z';

    if(output->length > 0) {
        output->length = (size_t)(pos - (char*)output->data);
    } else {
        UA_String str = {(size_t)(pos - buffer), (UA_Byte*)buffer};
        return UA_String_copy(&str, output);
    }

    return UA_STATUSCODE_GOOD;
}

/* Key Value Map */

const UA_KeyValueMap UA_KEYVALUEMAP_NULL = {0, NULL};

UA_KeyValueMap *
UA_KeyValueMap_new(void) {
    return (UA_KeyValueMap*)UA_calloc(1, sizeof(UA_KeyValueMap));
}

UA_StatusCode
UA_KeyValueMap_set(UA_KeyValueMap *map,
                   const UA_QualifiedName key,
                   const UA_Variant *value) {
    if(map == NULL || value == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Key exists already */
    const UA_Variant *v = UA_KeyValueMap_get(map, key);
    if(v) {
        UA_Variant copyV;
        UA_StatusCode res = UA_Variant_copy(value, &copyV);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        UA_Variant *target = (UA_Variant*)(uintptr_t)v;
        UA_Variant_clear(target);
        *target = copyV;
        return UA_STATUSCODE_GOOD;
    }

    /* Append to the array */
    UA_KeyValuePair pair;
    pair.key = key;
    pair.value = *value;
    return UA_Array_appendCopy((void**)&map->map, &map->mapSize, &pair,
                               &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
}

UA_EXPORT UA_StatusCode
UA_KeyValueMap_setShallow(UA_KeyValueMap *map,
                          const UA_QualifiedName key,
                          UA_Variant *value) {
    if(map == NULL || value == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Key exists already */
    UA_Variant *target;
    const UA_Variant *v = UA_KeyValueMap_get(map, key);
    if(v) {
        target = (UA_Variant*)(uintptr_t)v;
        UA_Variant_clear(target);
    } else {
        /* Append to the array */
        UA_KeyValuePair pair;
        pair.key = key;
        UA_Variant_init(&pair.value);
        UA_StatusCode res =
            UA_Array_appendCopy((void**)&map->map, &map->mapSize, &pair,
                                &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        target = &map->map[map->mapSize-1].value;
    }

    *target = *value;
    target->storageType = UA_VARIANT_DATA_NODELETE;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_KeyValueMap_setScalar(UA_KeyValueMap *map,
                         const UA_QualifiedName key,
                         const void * UA_RESTRICT p,
                         const UA_DataType *type) {
    if(p == NULL || type == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_Variant v;
    UA_Variant_init(&v);
    v.type = type;
    v.arrayLength = 0;
    v.data = (void*)(uintptr_t)p;
    return UA_KeyValueMap_set(map, key, &v);
}

UA_StatusCode
UA_KeyValueMap_setScalarShallow(UA_KeyValueMap *map, const UA_QualifiedName key,
                                void *UA_RESTRICT p, const UA_DataType *type) {
    if(p == NULL || type == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_Variant v;
    UA_Variant_init(&v);
    v.type = type;
    v.arrayLength = 0;
    v.data = p;
    return UA_KeyValueMap_setShallow(map, key, &v);
}

const UA_Variant *
UA_KeyValueMap_get(const UA_KeyValueMap *map,
                   const UA_QualifiedName key) {
    if(!map)
        return NULL;
    for(size_t i = 0; i < map->mapSize; i++) {
        if(map->map[i].key.namespaceIndex == key.namespaceIndex &&
           UA_String_equal(&map->map[i].key.name, &key.name))
            return &map->map[i].value;

    }
    return NULL;
}

UA_Boolean
UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map) {
    if(!map)
        return true;
    return map->mapSize == 0;
}

const void *
UA_KeyValueMap_getScalar(const UA_KeyValueMap *map,
                         const UA_QualifiedName key,
                         const UA_DataType *type) {
    const UA_Variant *v = UA_KeyValueMap_get(map, key);
    if(!v || !UA_Variant_hasScalarType(v, type))
        return NULL;
    return v->data;
}

void
UA_KeyValueMap_clear(UA_KeyValueMap *map) {
    if(!map)
        return;
    if(map->mapSize > 0) {
        UA_Array_delete(map->map, map->mapSize, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
        map->mapSize = 0;
    }
}

void
UA_KeyValueMap_delete(UA_KeyValueMap *map) {
    UA_KeyValueMap_clear(map);
    UA_free(map);
}

UA_StatusCode
UA_KeyValueMap_remove(UA_KeyValueMap *map,
                      const UA_QualifiedName key) {
    if(!map)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_KeyValuePair *m = map->map;
    size_t s = map->mapSize;
    size_t i = 0;
    for(; i < s; i++) {
        if(m[i].key.namespaceIndex == key.namespaceIndex &&
           UA_String_equal(&m[i].key.name, &key.name))
            break;
    }
    if(i == s)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Clean the slot and move the last entry to fill the slot */
    UA_KeyValuePair_clear(&m[i]);
    if(s > 1 && i < s - 1) {
        m[i] = m[s-1];
        UA_KeyValuePair_init(&m[s-1]);
    }

    /* In case resize fails, keep the longer original array around. Resize never
     * fails when reducing the size to zero. */
    UA_StatusCode res =
        UA_Array_resize((void**)&map->map, &map->mapSize, map->mapSize - 1,
                          &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    /* Adjust map->mapSize only when UA_Array_resize() failed. On success, the
     * value has already been decremented by UA_Array_resize(). */
    if(res != UA_STATUSCODE_GOOD)
        map->mapSize--;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst) {
    if(!dst)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!src) {
        dst->map = NULL;
        dst->mapSize = 0;
        return UA_STATUSCODE_GOOD;
    }
    UA_StatusCode res = UA_Array_copy(src->map, src->mapSize, (void**)&dst->map,
                                      &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res == UA_STATUSCODE_GOOD)
        dst->mapSize = src->mapSize;
    return res;
}

UA_Boolean
UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key) {
    if(!map)
        return false;
    for(size_t i = 0; i < map->mapSize; ++i) {
        if(UA_QualifiedName_equal(&map->map[i].key, &key))
            return true;
    }
    return false;
}

UA_StatusCode
UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs) {
    if(!lhs)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!rhs)
        return UA_STATUSCODE_GOOD;

    UA_KeyValueMap merge;
    UA_StatusCode res = UA_KeyValueMap_copy(lhs, &merge);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    for(size_t i = 0; i < rhs->mapSize; ++i) {
        res = UA_KeyValueMap_set(&merge, rhs->map[i].key, &rhs->map[i].value);
        if(res != UA_STATUSCODE_GOOD) {
            UA_KeyValueMap_clear(&merge);
            return res;
        }
    }

    UA_KeyValueMap_clear(lhs);
    *lhs = merge;
    return UA_STATUSCODE_GOOD;
}

/***************************/
/* Random Number Generator */
/***************************/

/* TODO is this safe for multithreading? */
static pcg32_random_t UA_rng = PCG32_INITIALIZER;

void
UA_random_seed(u64 seed) {
    pcg32_srandom_r(&UA_rng, seed, (u64)UA_DateTime_now());
}

void
UA_random_seed_deterministic(UA_UInt64 seed) {
    pcg32_srandom_r(&UA_rng, seed, 0);
}

u32
UA_UInt32_random(void) {
    return (u32)pcg32_random_r(&UA_rng);
}

UA_Guid
UA_Guid_random(void) {
    UA_Guid result;
    result.data1 = (u32)pcg32_random_r(&UA_rng);
    u32 r = (u32)pcg32_random_r(&UA_rng);
    result.data2 = (u16) r;
    result.data3 = (u16) (r >> 16);
    r = (u32)pcg32_random_r(&UA_rng);
    result.data4[0] = (u8)r;
    result.data4[1] = (u8)(r >> 4);
    result.data4[2] = (u8)(r >> 8);
    result.data4[3] = (u8)(r >> 12);
    r = (u32)pcg32_random_r(&UA_rng);
    result.data4[4] = (u8)r;
    result.data4[5] = (u8)(r >> 4);
    result.data4[6] = (u8)(r >> 8);
    result.data4[7] = (u8)(r >> 12);
    return result;
}

/********************/
/* Malloc Singleton */
/********************/

#ifdef UA_ENABLE_MALLOC_SINGLETON
# include <stdlib.h>
UA_EXPORT UA_THREAD_LOCAL void * (*UA_mallocSingleton)(size_t size) = malloc;
UA_EXPORT UA_THREAD_LOCAL void (*UA_freeSingleton)(void *ptr) = free;
UA_EXPORT UA_THREAD_LOCAL void * (*UA_callocSingleton)(size_t nelem, size_t elsize) = calloc;
UA_EXPORT UA_THREAD_LOCAL void * (*UA_reallocSingleton)(void *ptr, size_t size) = realloc;
#endif

/************************/
/* ReferenceType Lookup */
/************************/

typedef struct {
    UA_String browseName;
    UA_UInt32 identifier;
} RefTypeName;

#define KNOWNREFTYPES 17
static const RefTypeName knownRefTypes[KNOWNREFTYPES] = {
    {UA_STRING_STATIC("References"), UA_NS0ID_REFERENCES},
    {UA_STRING_STATIC("HierachicalReferences"), UA_NS0ID_HIERARCHICALREFERENCES},
    {UA_STRING_STATIC("NonHierachicalReferences"), UA_NS0ID_NONHIERARCHICALREFERENCES},
    {UA_STRING_STATIC("HasChild"), UA_NS0ID_HASCHILD},
    {UA_STRING_STATIC("Aggregates"), UA_NS0ID_AGGREGATES},
    {UA_STRING_STATIC("HasComponent"), UA_NS0ID_HASCOMPONENT},
    {UA_STRING_STATIC("HasProperty"), UA_NS0ID_HASPROPERTY},
    {UA_STRING_STATIC("HasOrderedComponent"), UA_NS0ID_HASORDEREDCOMPONENT},
    {UA_STRING_STATIC("HasSubtype"), UA_NS0ID_HASSUBTYPE},
    {UA_STRING_STATIC("Organizes"), UA_NS0ID_ORGANIZES},
    {UA_STRING_STATIC("HasModellingRule"), UA_NS0ID_HASMODELLINGRULE},
    {UA_STRING_STATIC("HasTypeDefinition"), UA_NS0ID_HASTYPEDEFINITION},
    {UA_STRING_STATIC("HasEncoding"), UA_NS0ID_HASENCODING},
    {UA_STRING_STATIC("GeneratesEvent"), UA_NS0ID_GENERATESEVENT},
    {UA_STRING_STATIC("AlwaysGeneratesEvent"), UA_NS0ID_ALWAYSGENERATESEVENT},
    {UA_STRING_STATIC("HasEventSource"), UA_NS0ID_HASEVENTSOURCE},
    {UA_STRING_STATIC("HasNotifier"), UA_NS0ID_HASNOTIFIER}
};

UA_StatusCode
lookupRefType(UA_Server *server, UA_QualifiedName *qn, UA_NodeId *outRefTypeId) {
    /* Check well-known ReferenceTypes first */
    if(qn->namespaceIndex == 0) {
        for(size_t i = 0; i < KNOWNREFTYPES; i++) {
            if(UA_String_equal(&qn->name, &knownRefTypes[i].browseName)) {
                *outRefTypeId = UA_NODEID_NUMERIC(0, knownRefTypes[i].identifier);
                return UA_STATUSCODE_GOOD;
            }
        }
    }

    /* Browse the information model. Return the first results if the browse name
     * in the hierarchy is ambiguous. */
    if(server) {
        UA_BrowseDescription bd;
        UA_BrowseDescription_init(&bd);
        bd.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCES);
        bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
        bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
        bd.nodeClassMask = UA_NODECLASS_REFERENCETYPE;

        size_t resultsSize = 0;
        UA_ExpandedNodeId *results = NULL;
        UA_StatusCode res =
            UA_Server_browseRecursive(server, &bd, &resultsSize, &results);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        for(size_t i = 0; i < resultsSize; i++) {
            UA_QualifiedName bn;
            UA_Server_readBrowseName(server, results[i].nodeId, &bn);
            if(UA_QualifiedName_equal(qn, &bn)) {
                UA_QualifiedName_clear(&bn);
                *outRefTypeId = results[i].nodeId;
                UA_NodeId_clear(&results[i].nodeId);
                UA_Array_delete(results, resultsSize, &UA_TYPES[UA_TYPES_NODEID]);
                return UA_STATUSCODE_GOOD;
            }
            UA_QualifiedName_clear(&bn);
        }

        UA_Array_delete(results, resultsSize, &UA_TYPES[UA_TYPES_NODEID]);
    }

    return UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
getRefTypeBrowseName(const UA_NodeId *refTypeId, UA_String *outBN) {
    /* Canonical name known? */
    if(refTypeId->namespaceIndex == 0 &&
       refTypeId->identifierType == UA_NODEIDTYPE_NUMERIC) {
        for(size_t i = 0; i < KNOWNREFTYPES; i++) {
            if(refTypeId->identifier.numeric != knownRefTypes[i].identifier)
                continue;
            memcpy(outBN->data, knownRefTypes[i].browseName.data, knownRefTypes[i].browseName.length);
            outBN->length = knownRefTypes[i].browseName.length;
            return UA_STATUSCODE_GOOD;
        }
    }

    /* Print the NodeId */
    return UA_NodeId_print(refTypeId, outBN);
}

/************************/
/* Printing and Parsing */
/************************/

static UA_INLINE UA_Boolean
isHex(u8 c) {
    return ((c >= 'a' && c <= 'f') ||
            (c >= 'A' && c <= 'F') ||
            (c >= '0' && c <= '9'));
}

UA_StatusCode
UA_String_unescape(UA_String *str, UA_Boolean copyEscape, UA_Escaping esc) {
    if(esc == UA_ESCAPING_NONE)
        return UA_STATUSCODE_GOOD;

    /* Does the string need escaping? */
    UA_String tmp;
    status res = UA_STATUSCODE_GOOD;
    u8 *pos = str->data;
    u8 *end = str->data + str->length;
    u8 escape_char = (esc == UA_ESCAPING_PERCENT ||
                      esc == UA_ESCAPING_PERCENT_EXTENDED) ? '%' : '&';
    for(; pos < end; pos++) {
        if(*pos == escape_char)
            goto escape;
    }

    return UA_STATUSCODE_GOOD;

 escape:
    if(copyEscape) {
        res = UA_String_copy(str, &tmp);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        pos = tmp.data;
        end = tmp.data + tmp.length;
    }

    u8 byte = 0;
    u8 *writepos = pos;

    res = UA_STATUSCODE_BADDECODINGERROR;
    if(esc == UA_ESCAPING_PERCENT ||
       esc == UA_ESCAPING_PERCENT_EXTENDED) {
        /* Percent-Escaping */
        for(; pos < end; pos++) {
            if(*pos == '%') {
                if(pos + 2 >= end || !isHex(pos[1]) || !isHex(pos[2]))
                    goto out;
                if(pos[1] >= 'a')
                    byte = pos[1] - ('a' - 10);
                else if(pos[1] >= 'A')
                    byte = pos[1] - ('A' - 10);
                else
                    byte = pos[1] - '0';
                byte <<= 4;

                if(pos[2] >= 'a')
                    byte += (u8)(pos[2] - ('a' - 10));
                else if(pos[2] >= 'A')
                    byte += (u8)(pos[2] - ('A' - 10));
                else
                    byte += (u8)(pos[2] - '0');

                pos += 2;
                *writepos++ = byte;
                continue;
            }
            *writepos++ = *pos;
        }
    } else {
        /* And-Escaping */
        for(; pos < end; pos++) {
            if(*pos == '&') {
                pos++;
                if(pos == end)
                    goto out;
            }
            *writepos++ = *pos;
        }
    }
    res = UA_STATUSCODE_GOOD;

 out:
    if(copyEscape) {
        tmp.length = (size_t)(writepos - tmp.data);
        if(tmp.length == 0)
            UA_String_clear(&tmp);
        if(res == UA_STATUSCODE_GOOD)
            *str = tmp;
        else
            UA_String_clear(&tmp);
    } else if(res == UA_STATUSCODE_GOOD) {
        str->length = (size_t)(writepos - str->data);
    }
    return res;
}

static const u8 hexchars[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

size_t
UA_String_escapedSize(const UA_String s, UA_Escaping esc) {
    /* Find out the overhead from escaping */
    size_t overhead = 0;
    for(size_t j = 0; j < s.length; j++) {
        if(esc == UA_ESCAPING_AND_EXTENDED)
            overhead += isReservedAndExtended(s.data[j]);
        else if(esc == UA_ESCAPING_AND)
            overhead += isReservedAnd(s.data[j]);
        else if(esc == UA_ESCAPING_PERCENT)
            overhead += (isReservedPercent(s.data[j]) ? 2 : 0);
        else /* if(esc == UA_ESCAPING_PERCENT_EXTENDED) */
            overhead += (isReservedPercentExtended(s.data[j]) ? 2 : 0);
    }

    return s.length + overhead;
}

size_t
UA_String_escapeInsert(u8 *pos, const UA_String s2, UA_Escaping esc) {
    u8 *begin = pos;

    if(esc == UA_ESCAPING_NONE) {
        for(size_t j = 0; j < s2.length; j++)
            *pos++ = s2.data[j];
    } else if(esc == UA_ESCAPING_PERCENT || esc == UA_ESCAPING_PERCENT_EXTENDED) {
        for(size_t j = 0; j < s2.length; j++) {
            UA_Boolean reserved = (esc == UA_ESCAPING_PERCENT_EXTENDED) ?
                isReservedPercentExtended(s2.data[j]) : isReservedPercent(s2.data[j]);
            if(UA_LIKELY(!reserved)) {
                *pos++ = s2.data[j];
            } else {
                *pos++ = '%';
                *pos++ = hexchars[s2.data[j] >> 4];
                *pos++ = hexchars[s2.data[j] & 0x0f];
            }
        }
    } else {
        for(size_t j = 0; j < s2.length; j++) {
            UA_Boolean reserved = (esc == UA_ESCAPING_AND_EXTENDED) ?
                isReservedAndExtended(s2.data[j]) : isReservedAnd(s2.data[j]);
            if(reserved)
                *pos++ = '&';
            *pos++ = s2.data[j];
        }
    }

    return (size_t)(pos - begin);
}

UA_StatusCode
UA_String_escapeAppend(UA_String *s, const UA_String s2, UA_Escaping esc) {
    if(esc == UA_ESCAPING_NONE)
        return UA_String_append(s, s2);

    /* Allocate memory for the additional escaped string */
    size_t escapedLength = UA_String_escapedSize(s2, esc);
    UA_Byte *buf = (UA_Byte*)
        UA_realloc(s->data, s->length + s2.length + escapedLength);
    if(!buf)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Escape and insert at the end */
    s->data = buf;
    UA_String_escapeInsert(s->data + s->length, s2, esc);
    s->length += escapedLength;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
moveTmpToOut(UA_String *tmp, UA_String *out) {
    /* Output has zero length */
    if(tmp->length == 0) {
        UA_assert(tmp->data == NULL);
        if(out->data == NULL)
            out->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        out->length = 0;
        return UA_STATUSCODE_GOOD;
    }

    /* No output buffer provided, return the tmp buffer */
    if(out->length == 0) {
        *out = *tmp;
        return UA_STATUSCODE_GOOD;
    }

    /* The provided buffer is too short */
    if(out->length < tmp->length) {
        UA_String_clear(tmp);
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    }

    /* Copy output to the provided buffer */
    memcpy(out->data, tmp->data, tmp->length);
    out->length = tmp->length;
    UA_String_clear(tmp);
    return UA_STATUSCODE_GOOD;
}

static const UA_NodeId hierarchicalRefs =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HIERARCHICALREFERENCES}};
static const UA_NodeId aggregatesRefs =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_AGGREGATES}};
static const UA_NodeId objectsFolder =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_OBJECTSFOLDER}};

static UA_StatusCode
printRelativePath(const UA_RelativePath *rp, UA_String *out, UA_Escaping esc) {
    UA_String tmp = UA_STRING_NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < rp->elementsSize && res == UA_STATUSCODE_GOOD; i++) {
        /* Print the reference type */
        UA_RelativePathElement *elm = &rp->elements[i];
        if(UA_NodeId_equal(&hierarchicalRefs, &elm->referenceTypeId) &&
           !elm->isInverse && elm->includeSubtypes) {
            res |= UA_String_append(&tmp, UA_STRING("/"));
        } else if(esc == UA_ESCAPING_AND &&
                  UA_NodeId_equal(&aggregatesRefs, &elm->referenceTypeId) &&
                  !elm->isInverse && elm->includeSubtypes) {
            res |= UA_String_append(&tmp, UA_STRING("."));
        } else {
            res |= UA_String_append(&tmp, UA_STRING("<"));
            if(!elm->includeSubtypes)
                res |= UA_String_append(&tmp, UA_STRING("#"));
            if(elm->isInverse)
                res |= UA_String_append(&tmp, UA_STRING("!"));
            if(res != UA_STATUSCODE_GOOD)
                break;

            UA_Byte bnBuf[512];
            UA_String bnBufStr = {512, bnBuf};
            res = getRefTypeBrowseName(&elm->referenceTypeId, &bnBufStr);
            if(res != UA_STATUSCODE_GOOD) {
                UA_String_init(&bnBufStr);
                res = getRefTypeBrowseName(&elm->referenceTypeId, &bnBufStr);
                if(res != UA_STATUSCODE_GOOD)
                    break;
            }
            res |= UA_String_escapeAppend(&tmp, bnBufStr, esc);
            res |= UA_String_append(&tmp, UA_STRING(">"));
            if(bnBufStr.data != bnBuf)
                UA_String_clear(&bnBufStr);
        }

        /* Print the qualified name */
        UA_QualifiedName *qn = &elm->targetName;
        if(qn->namespaceIndex > 0) {
            char nsStr[8]; /* Enough for a uint16 */
            itoaUnsigned(qn->namespaceIndex, nsStr, 10);
            res |= UA_String_append(&tmp, UA_STRING(nsStr));
            res |= UA_String_append(&tmp, UA_STRING(":"));
        }
        res |= UA_String_escapeAppend(&tmp, qn->name, esc);
    }

    /* Encoding failed, clean up */
    if(res != UA_STATUSCODE_GOOD) {
        UA_String_clear(&tmp);
        return res;
    }

    return moveTmpToOut(&tmp, out);
}

UA_StatusCode
UA_RelativePath_print(const UA_RelativePath *rp, UA_String *out) {
    return printRelativePath(rp, out, UA_ESCAPING_AND);
}

static UA_NodeId baseEventTypeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEEVENTTYPE}};

#ifdef UA_TYPES_SIMPLEATTRIBUTEOPERAND

UA_StatusCode
UA_SimpleAttributeOperand_print(const UA_SimpleAttributeOperand *sao, UA_String *out) {
    UA_RelativePathElement rpe;
    UA_String tmp = UA_STRING_NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Print the TypeDefinitionId */
    if(!UA_NodeId_equal(&baseEventTypeId, &sao->typeDefinitionId)) {
        UA_Byte nodeIdBuf[512];
        UA_String nodeIdBufStr = {512, nodeIdBuf};
        res |= nodeId_printEscape(&sao->typeDefinitionId, &nodeIdBufStr,
                                  NULL, UA_ESCAPING_PERCENT);
        res |= UA_String_append(&tmp, nodeIdBufStr);
    }

    /* Print the BrowsePath */
    UA_RelativePathElement_init(&rpe);
    rpe.includeSubtypes = true;
    rpe.referenceTypeId = hierarchicalRefs;
    UA_RelativePath rp = {1, &rpe};
    for(size_t i = 0; i < sao->browsePathSize; i++) {
        UA_String rpstr = UA_STRING_NULL;
        UA_assert(rpstr.data == NULL && rpstr.length == 0); /* pacify clang scan-build */
        rpe.targetName = sao->browsePath[i];
        res |= printRelativePath(&rp, &rpstr, UA_ESCAPING_PERCENT);
        res |= UA_String_append(&tmp, rpstr);
        UA_String_clear(&rpstr);
    }

    /* Print the attribute name */
    if(sao->attributeId != UA_ATTRIBUTEID_VALUE) {
        const char *attrName = UA_AttributeId_name((UA_AttributeId)sao->attributeId);
        res |= UA_String_append(&tmp, UA_STRING("#"));
        res |= UA_String_append(&tmp, UA_STRING((char*)(uintptr_t)attrName));
    }

    /* Print the IndexRange */
    if(sao->indexRange.length > 0) {
        res |= UA_String_append(&tmp, UA_STRING("["));
        res |= UA_String_append(&tmp, sao->indexRange);
        res |= UA_String_append(&tmp, UA_STRING("]"));
    }

    /* Encoding failed, clean up */
    if(res != UA_STATUSCODE_GOOD) {
        UA_String_clear(&tmp);
        return res;
    }

    return moveTmpToOut(&tmp, out);
}

#endif /* UA_TYPES_SIMPLEATTRIBUTEOPERAND */

#ifdef UA_TYPES_ATTRIBUTEOPERAND

UA_StatusCode
UA_AttributeOperand_print(const UA_AttributeOperand *ao,
                          UA_String *out) {
    UA_String tmp = UA_STRING_NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Print the TypeDefinitionId */
    if(!UA_NodeId_equal(&objectsFolder, &ao->nodeId)) {
        UA_Byte nodeIdBuf[512];
        UA_String nodeIdBufStr = {512, nodeIdBuf};
        res |= nodeId_printEscape(&ao->nodeId, &nodeIdBufStr,
                                  NULL, UA_ESCAPING_PERCENT_EXTENDED);
        res |= UA_String_append(&tmp, nodeIdBufStr);
    }

    /* Print the BrowsePath */
    UA_String rpstr = UA_STRING_NULL;
    UA_assert(rpstr.data == NULL && rpstr.length == 0); /* pacify clang scan-build */
    res |= printRelativePath(&ao->browsePath, &rpstr, UA_ESCAPING_PERCENT_EXTENDED);
    res |= UA_String_append(&tmp, rpstr);
    UA_String_clear(&rpstr);

    /* Print the attribute name */
    if(ao->attributeId != UA_ATTRIBUTEID_VALUE) {
        const char *attrName= UA_AttributeId_name((UA_AttributeId)ao->attributeId);
        res |= UA_String_append(&tmp, UA_STRING("#"));
        res |= UA_String_append(&tmp, UA_STRING((char*)(uintptr_t)attrName));
    }

    /* Print the IndexRange */
    if(ao->indexRange.length > 0) {
        res |= UA_String_append(&tmp, UA_STRING("["));
        res |= UA_String_append(&tmp, ao->indexRange);
        res |= UA_String_append(&tmp, UA_STRING("]"));
    }

    /* Encoding failed, clean up */
    if(res != UA_STATUSCODE_GOOD) {
        UA_String_clear(&tmp);
        return res;
    }

    return moveTmpToOut(&tmp, out);
}

#endif /* UA_TYPES_ATTRIBUTEOPERAND */

UA_StatusCode
UA_ReadValueId_print(const UA_ReadValueId *rvi, UA_String *out) {
    UA_String tmp = UA_STRING_NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Print the TypeDefinitionId */
    if(!UA_NodeId_equal(&UA_NODEID_NULL, &rvi->nodeId)) {
        UA_Byte nodeIdBuf[512];
        UA_String nodeIdBufStr = {512, nodeIdBuf};
        res |= nodeId_printEscape(&rvi->nodeId, &nodeIdBufStr,
                                  NULL, UA_ESCAPING_PERCENT);
        res |= UA_String_append(&tmp, nodeIdBufStr);
    }

    /* Print the attribute name */
    if(rvi->attributeId != UA_ATTRIBUTEID_VALUE) {
        const char *attrName= UA_AttributeId_name((UA_AttributeId)rvi->attributeId);
        res |= UA_String_append(&tmp, UA_STRING("#"));
        res |= UA_String_append(&tmp, UA_STRING((char*)(uintptr_t)attrName));
    }

    /* Print the IndexRange */
    if(rvi->indexRange.length > 0) {
        res |= UA_String_append(&tmp, UA_STRING("["));
        res |= UA_String_append(&tmp, rvi->indexRange);
        res |= UA_String_append(&tmp, UA_STRING("]"));
    }

    /* Encoding failed, clean up */
    if(res != UA_STATUSCODE_GOOD) {
        UA_String_clear(&tmp);
        return res;
    }

    return moveTmpToOut(&tmp, out);
}

/************************/
/* Cryptography Helpers */
/************************/

UA_ByteString
getLeafCertificate(UA_ByteString chain) {
    /* Detect DER encoded X.509 v3 certificate. If the DER detection fails,
     * return the entire chain.
     *
     * The OPC UA standard requires this to be DER. But we also allow other
     * formats like PEM. Afterwards it depends on the crypto backend to parse
     * it. mbedTLS and OpenSSL detect the format automatically. */
    if(chain.length < 4 || chain.data[0] != 0x30 || chain.data[1] != 0x82)
        return chain;

    /* The certificate length is encoded in the next 2 bytes. */
    size_t leafLen = 4; /* Magic numbers + length bytes */
    leafLen += (size_t)(((uint16_t)chain.data[2]) << 8);
    leafLen += chain.data[3];

    /* Consistency check */
    if(leafLen > chain.length)
        return UA_BYTESTRING_NULL;

    /* Adjust the length and return */
    chain.length = leafLen;
    return chain;
}

UA_Boolean
UA_constantTimeEqual(const void *ptr1, const void *ptr2, size_t length) {
    volatile const UA_Byte *a = (volatile const UA_Byte *)ptr1;
    volatile const UA_Byte *b = (volatile const UA_Byte *)ptr2;
    volatile UA_Byte c = 0;
    for(size_t i = 0; i < length; ++i) {
        UA_Byte x = a[i], y = b[i];
        c = c | (x ^ y);
    }
    return !c;
}

void
UA_ByteString_memZero(UA_ByteString *bs) {
#if defined(__STDC_LIB_EXT1__)
   memset_s(bs->data, bs->length, 0, bs->length);
#elif defined(UA_ARCHITECTURE_WIN32)
   SecureZeroMemory(bs->data, bs->length);
#else
   volatile unsigned char *volatile ptr =
       (volatile unsigned char *)bs->data;
   size_t i = 0;
   size_t maxLen = bs->length;
   while(i < maxLen) {
       ptr[i++] = 0;
   }
#endif
}

UA_Boolean
UA_TrustListDataType_contains(const UA_TrustListDataType *trustList,
                              const UA_ByteString *certificate,
                              UA_TrustListMasks specifiedList) {
    if(!trustList || !certificate)
        return false;

    if(specifiedList & UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES) {
        for(size_t i = 0; i < trustList->trustedCertificatesSize; i++) {
            if(UA_ByteString_equal(certificate, &trustList->trustedCertificates[i]))
                return true;
        }
    }
    if(specifiedList & UA_TRUSTLISTMASKS_TRUSTEDCRLS) {
        for(size_t i = 0; i < trustList->trustedCrlsSize; i++) {
            if(UA_ByteString_equal(certificate, &trustList->trustedCrls[i]))
                return true;
        }
    }
    if(specifiedList & UA_TRUSTLISTMASKS_ISSUERCERTIFICATES) {
        for(size_t i = 0; i < trustList->issuerCertificatesSize; i++) {
            if(UA_ByteString_equal(certificate, &trustList->issuerCertificates[i]))
                return true;
        }
    }
    if(specifiedList & UA_TRUSTLISTMASKS_ISSUERCRLS) {
        for(size_t i = 0; i < trustList->issuerCrlsSize; i++) {
            if(UA_ByteString_equal(certificate, &trustList->issuerCrls[i]))
                return true;
        }
    }

    return false;
}

UA_StatusCode
UA_TrustListDataType_add(const UA_TrustListDataType *src, UA_TrustListDataType *dst) {
    if(!dst)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!src) {
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    if(src->specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES) {
        if(dst->trustedCertificates == NULL)
            dst->trustedCertificates = (UA_ByteString *)UA_Array_new(0, &UA_TYPES[UA_TYPES_BYTESTRING]);
        for(size_t i = 0; i < src->trustedCertificatesSize; i++) {
            if(UA_TrustListDataType_contains(dst, &src->trustedCertificates[i],
                                             UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES)) {
                continue;
            }
            retval = UA_Array_appendCopy((void**)&dst->trustedCertificates, &dst->trustedCertificatesSize,
                                      &src->trustedCertificates[i], &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                return retval;
            }
        }
        dst->specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES;
    }
    if(src->specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCRLS) {
        if(dst->trustedCrls == NULL)
            dst->trustedCrls = (UA_ByteString *)UA_Array_new(0, &UA_TYPES[UA_TYPES_BYTESTRING]);
        for(size_t i = 0; i < src->trustedCrlsSize; i++) {
            if(UA_TrustListDataType_contains(dst, &src->trustedCrls[i],
                                             UA_TRUSTLISTMASKS_TRUSTEDCRLS)) {
                continue;
            }
            retval = UA_Array_appendCopy((void**)&dst->trustedCrls, &dst->trustedCrlsSize,
                                      &src->trustedCrls[i], &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                return retval;
            }
        }
        dst->specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCRLS;
    }
    if(src->specifiedLists & UA_TRUSTLISTMASKS_ISSUERCERTIFICATES) {
        if(dst->issuerCertificates == NULL)
            dst->issuerCertificates = (UA_ByteString *)UA_Array_new(0, &UA_TYPES[UA_TYPES_BYTESTRING]);
        for(size_t i = 0; i < src->issuerCertificatesSize; i++) {
            if(UA_TrustListDataType_contains(dst, &src->issuerCertificates[i],
                                            UA_TRUSTLISTMASKS_ISSUERCERTIFICATES)) {
                continue;
            }
            retval = UA_Array_appendCopy((void**)&dst->issuerCertificates, &dst->issuerCertificatesSize,
                                      &src->issuerCertificates[i], &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                return retval;
            }
        }
        dst->specifiedLists |= UA_TRUSTLISTMASKS_ISSUERCERTIFICATES;
    }
    if(src->specifiedLists & UA_TRUSTLISTMASKS_ISSUERCRLS) {
        if(dst->issuerCrls == NULL)
            dst->issuerCrls = (UA_ByteString *)UA_Array_new(0, &UA_TYPES[UA_TYPES_BYTESTRING]);
        for(size_t i = 0; i < src->issuerCrlsSize; i++) {
            if(UA_TrustListDataType_contains(dst, &src->issuerCrls[i],
                                            UA_TRUSTLISTMASKS_ISSUERCRLS)) {
                continue;
            }
            retval = UA_Array_appendCopy((void**)&dst->issuerCrls, &dst->issuerCrlsSize,
                                      &src->issuerCrls[i], &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                return retval;
            }
        }
        dst->specifiedLists |= UA_TRUSTLISTMASKS_ISSUERCRLS;
    }

    return retval;
}

UA_StatusCode
UA_TrustListDataType_set(const UA_TrustListDataType *src, UA_TrustListDataType *dst) {
    if(src->specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES) {
        UA_Array_delete(dst->trustedCertificates, dst->trustedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->trustedCertificates = NULL;
        dst->trustedCertificatesSize = 0;
    }
    if(src->specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCRLS) {
        UA_Array_delete(dst->trustedCrls, dst->trustedCrlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->trustedCrls = NULL;
        dst->trustedCrlsSize = 0;
    }
    if(src->specifiedLists & UA_TRUSTLISTMASKS_ISSUERCERTIFICATES) {
        UA_Array_delete(dst->issuerCertificates, dst->issuerCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->issuerCertificates = NULL;
        dst->issuerCertificatesSize = 0;
    }
    if(src->specifiedLists & UA_TRUSTLISTMASKS_ISSUERCRLS) {
        UA_Array_delete(dst->issuerCrls, dst->issuerCrlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->issuerCrls = NULL;
        dst->issuerCrlsSize = 0;
    }
    return UA_TrustListDataType_add(src, dst);
}

UA_StatusCode
UA_TrustListDataType_remove(const UA_TrustListDataType *src, UA_TrustListDataType *dst) {
    if(!dst)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!src) {
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* remove trusted certificates */
    if(dst->trustedCertificatesSize > 0 && src->trustedCertificatesSize > 0) {
        UA_ByteString *newList = (UA_ByteString*)UA_calloc(dst->trustedCertificatesSize, sizeof(UA_ByteString));
        size_t newListSize = 0;
        size_t oldListSize = dst->trustedCertificatesSize;
        UA_Boolean isContained = false;
        for(size_t i = 0; i < dst->trustedCertificatesSize; i++) {
            for(size_t j = 0; j < src->trustedCertificatesSize; j++) {
                if(UA_ByteString_equal(&dst->trustedCertificates[i], &src->trustedCertificates[j]))
                    isContained = true;
            }
            if(!isContained) {
                UA_ByteString_copy(&dst->trustedCertificates[i], &newList[newListSize]);
                newListSize += 1;
            }
            isContained = false;
        }
        if(newListSize < dst->trustedCertificatesSize) {
            if(newListSize == 0) {
                UA_free(newList);
                newList = NULL;
            } else {
                retval = UA_Array_resize((void**)&newList, &oldListSize, newListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
                if(retval != UA_STATUSCODE_GOOD) {
                    UA_free(newList);
                    return retval;
                }
            }
        }
        UA_Array_delete(dst->trustedCertificates, dst->trustedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->trustedCertificatesSize = 0;
        dst->trustedCertificates = newList;
        dst->trustedCertificatesSize = newListSize;
    }

    /* remove issuer certificates */
    if(dst->issuerCertificatesSize > 0 && src->issuerCertificatesSize > 0) {
        UA_ByteString *newList = (UA_ByteString*)UA_calloc(dst->issuerCertificatesSize, sizeof(UA_ByteString));
        size_t newListSize = 0;
        size_t oldListSize = dst->issuerCertificatesSize;
        UA_Boolean isContained = false;
        for(size_t i = 0; i < dst->issuerCertificatesSize; i++) {
            for(size_t j = 0; j < src->issuerCertificatesSize; j++) {
                if(UA_ByteString_equal(&dst->issuerCertificates[i], &src->issuerCertificates[j]))
                    isContained = true;
            }
            if(!isContained) {
                UA_ByteString_copy(&dst->issuerCertificates[i], &newList[newListSize]);
                newListSize += 1;
            }
            isContained = false;
        }
        if(newListSize < dst->issuerCertificatesSize) {
            if(newListSize == 0) {
                UA_free(newList);
                newList = NULL;
            } else {
                retval = UA_Array_resize((void**)&newList, &oldListSize, newListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
                if(retval != UA_STATUSCODE_GOOD) {
                    UA_free(newList);
                    return retval;
                }
            }
        }
        UA_Array_delete(dst->issuerCertificates, dst->issuerCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->issuerCertificatesSize = 0;
        dst->issuerCertificates = newList;
        dst->issuerCertificatesSize = newListSize;
    }

    /* remove trusted crls */
    if(dst->trustedCrlsSize > 0 && src->trustedCrlsSize > 0) {
        UA_ByteString *newList = (UA_ByteString*)UA_calloc(dst->trustedCrlsSize, sizeof(UA_ByteString));
        size_t newListSize = 0;
        size_t oldListSize = dst->trustedCrlsSize;
        UA_Boolean isContained = false;
        for(size_t i = 0; i < dst->trustedCrlsSize; i++) {
            for(size_t j = 0; j < src->trustedCrlsSize; j++) {
                if(UA_ByteString_equal(&dst->trustedCrls[i], &src->trustedCrls[j]))
                    isContained = true;
            }
            if(!isContained) {
                UA_ByteString_copy(&dst->trustedCrls[i], &newList[newListSize]);
                newListSize += 1;
            }
            isContained = false;
        }
        if(newListSize < dst->trustedCrlsSize) {
            if(newListSize == 0) {
                UA_free(newList);
                newList = NULL;
            } else {
                retval = UA_Array_resize((void**)&newList, &oldListSize, newListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
                if(retval != UA_STATUSCODE_GOOD) {
                    UA_free(newList);
                    return retval;
                }
            }
        }
        UA_Array_delete(dst->trustedCrls, dst->trustedCrlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->trustedCrlsSize = 0;
        dst->trustedCrls = newList;
        dst->trustedCrlsSize = newListSize;
    }

    /* remove issuer crls */
    if(dst->issuerCrlsSize > 0 && src->issuerCrlsSize > 0) {
        UA_ByteString *newList = (UA_ByteString*)UA_calloc(dst->issuerCrlsSize, sizeof(UA_ByteString));
        size_t newListSize = 0;
        size_t oldListSize = dst->issuerCrlsSize;
        UA_Boolean isContained = false;
        for(size_t i = 0; i < dst->issuerCrlsSize; i++) {
            for(size_t j = 0; j < src->issuerCrlsSize; j++) {
                if(UA_ByteString_equal(&dst->issuerCrls[i], &src->issuerCrls[j]))
                    isContained = true;
            }
            if(!isContained) {
                UA_ByteString_copy(&dst->issuerCrls[i], &newList[newListSize]);
                newListSize += 1;
            }
            isContained = false;
        }
        if(newListSize < dst->issuerCrlsSize) {
            if(newListSize == 0) {
                UA_free(newList);
                newList = NULL;
            } else {
                retval = UA_Array_resize((void**)&newList, &oldListSize, newListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
                if(retval != UA_STATUSCODE_GOOD) {
                    UA_free(newList);
                    return retval;
                }
            }
        }
        UA_Array_delete(dst->issuerCrls, dst->issuerCrlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        dst->issuerCrlsSize = 0;
        dst->issuerCrls = newList;
        dst->issuerCrlsSize = newListSize;
    }

    return retval;
}

UA_UInt32
UA_TrustListDataType_getSize(const UA_TrustListDataType *trustList) {
    UA_UInt32 size = 0;
    for(size_t i = 0; i < trustList->trustedCertificatesSize; i++) {
        size += (UA_UInt32)trustList->trustedCertificates[i].length;
    }
    for(size_t i = 0; i < trustList->trustedCrlsSize; i++) {
        size += (UA_UInt32)trustList->trustedCrls[i].length;
    }
    for(size_t i = 0; i < trustList->issuerCertificatesSize; i++) {
        size += (UA_UInt32)trustList->issuerCertificates[i].length;
    }
    for(size_t i = 0; i < trustList->issuerCrlsSize; i++) {
        size += (UA_UInt32)trustList->issuerCrls[i].length;
    }
    return size;
}

/**** amalgamated original file "/src/util/ua_types_lex.c" ****/

/* Generated by re2c 4.5.1 */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *
 */


/* Lexing and parsing of builtin data types. These are helper functions that not
 * required by the SDK internally. But they are useful for users who want to use
 * standard-specified humand readable encodings for NodeIds, etc.
 *
 * This compilation unit uses the re2c lexer generator. The final C source is
 * generated with the following script:
 *
 *   re2c -i --no-generation-date ua_types_lex.re > ua_types_lex.c
 *
 * In order that users of the SDK don't need to install re2c, always commit a
 * recent ua_types_lex.c if changes are made to the lexer. */

#define UA_MAXPATHLENGTH 128 /* Maximum relative path depth */

#define YYCURSOR pos
#define YYMARKER context.marker
#define YYPEEK() (YYCURSOR < end) ? *YYCURSOR : 0 /* The lexer sees a stream of
                                                   * \0 when the input ends*/
#define YYSKIP() ++YYCURSOR;
#define YYBACKUP() YYMARKER = YYCURSOR
#define YYRESTORE() YYCURSOR = YYMARKER
#define YYSTAGP(t) t = YYCURSOR
#define YYSTAGN(t) t = NULL
#define YYSHIFTSTAG(t, shift) t += shift

typedef struct {
    const u8 *marker;
    const u8 *yyt1;const u8 *yyt2;const u8 *yyt3;const u8 *yyt4;const u8 *yyt5;
} LexContext;



static UA_StatusCode
parse_guid(UA_Guid *guid, const UA_Byte *s, const UA_Byte *e) {
    size_t len = (size_t)(e - s);
    if(len != 36 || s[8] != '-' || s[13] != '-' || s[23] != '-')
        return UA_STATUSCODE_BADDECODINGERROR;

    UA_UInt32 tmp;
    if(UA_readNumberWithBase(s, 8, &tmp, 16) != 8)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data1 = tmp;

    if(UA_readNumberWithBase(&s[9], 4, &tmp, 16) != 4)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data2 = (UA_UInt16)tmp;

    if(UA_readNumberWithBase(&s[14], 4, &tmp, 16) != 4)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data3 = (UA_UInt16)tmp;

    if(UA_readNumberWithBase(&s[19], 2, &tmp, 16) != 2)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data4[0] = (UA_Byte)tmp;

    if(UA_readNumberWithBase(&s[21], 2, &tmp, 16) != 2)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data4[1] = (UA_Byte)tmp;

    for(size_t pos = 2, spos = 24; pos < 8; pos++, spos += 2) {
        if(UA_readNumberWithBase(&s[spos], 2, &tmp, 16) != 2)
            return UA_STATUSCODE_BADDECODINGERROR;
        guid->data4[pos] = (UA_Byte)tmp;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Guid_parse(UA_Guid *guid, const UA_String str) {
    UA_StatusCode res = parse_guid(guid, str.data, str.data + str.length);
    if(res != UA_STATUSCODE_GOOD)
        *guid = UA_GUID_NULL;
    return res;
}

static UA_StatusCode
escapedUri2Index(UA_String uri, UA_UInt16 *nsIndex,
                 const UA_NamespaceMapping *nsMapping) {
    if(!nsMapping)
        return UA_STATUSCODE_BADDECODINGERROR;
    UA_String tmp = uri; 
    status res = UA_String_unescape(&uri, true, UA_ESCAPING_PERCENT);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    res = UA_NamespaceMapping_uri2Index(nsMapping, uri, nsIndex);
    if(tmp.data != uri.data)
        UA_String_clear(&uri);
    return res;
}

static UA_StatusCode
parse_nodeid_body(UA_NodeId *id, const u8 *body, const u8 *end, UA_Escaping esc) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_String str = {(size_t)(end - (body+2)), (UA_Byte*)(uintptr_t)body + 2};
    switch(*body) {
    case 'i':
        id->identifierType = UA_NODEIDTYPE_NUMERIC;
        if(UA_readNumber(str.data, str.length, &id->identifier.numeric) != str.length)
            res = UA_STATUSCODE_BADDECODINGERROR;
        break;
    case 's':
        id->identifierType = UA_NODEIDTYPE_STRING;
        res |= UA_String_copy(&str, &id->identifier.string);
        res |= UA_String_unescape(&id->identifier.string, false, esc);
        break;
    case 'g':
        id->identifierType = UA_NODEIDTYPE_GUID;
        res = parse_guid(&id->identifier.guid, str.data, end);
        break;
    case 'b':
        /* For percent-escaping, base64url bytestring encoding is used. That
         * doesn't need to be escaped here. The and-escaping is not applied to
         * the NodeId identifier part. */
        id->identifierType = UA_NODEIDTYPE_BYTESTRING;
        id->identifier.byteString.data =
            UA_unbase64(str.data, str.length, &id->identifier.byteString.length);
        if(!id->identifier.byteString.data) {
            UA_assert(id->identifier.byteString.length == 0);
            res = UA_STATUSCODE_BADDECODINGERROR; /* Returned on error by UA_unbase64 */
        }
        break;
    default:
        res = UA_STATUSCODE_BADDECODINGERROR;
        break;
    }
    return res;
}

static UA_StatusCode
parse_nodeid(UA_NodeId *id, const u8 *pos, const u8 *end,
             UA_Escaping idEsc, const UA_NamespaceMapping *nsMapping) {
    *id = UA_NODEID_NULL; /* Reset the NodeId */
    LexContext context;
    memset(&context, 0, sizeof(LexContext));
    UA_Byte *begin = (UA_Byte*)(uintptr_t)pos;
    const u8 *ns = NULL, *nsu = NULL, *body = NULL;

    
{
	u8 yych;
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			goto yy3;
		case 'n': goto yy4;
		default: goto yy1;
	}
yy1:
	YYSKIP();
yy2:
	{ (void)pos; return UA_STATUSCODE_BADDECODINGERROR; }
yy3:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy5;
		default: goto yy2;
	}
yy4:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 's': goto yy6;
		default: goto yy2;
	}
yy5:
	YYSKIP();
	nsu = context.yyt2;
	ns = context.yyt1;
	YYSTAGP(body);
	YYSHIFTSTAG(body, -2);
	{ goto match; }
yy6:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy8;
		case 'u': goto yy9;
		default: goto yy7;
	}
yy7:
	YYRESTORE();
	goto yy2;
yy8:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(context.yyt1);
			goto yy10;
		default: goto yy7;
	}
yy9:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy11;
		default: goto yy7;
	}
yy10:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy10;
		case ';':
			YYSTAGN(context.yyt2);
			goto yy12;
		default: goto yy7;
	}
yy11:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy7;
		case ';':
			YYSTAGN(context.yyt1);
			YYSTAGP(context.yyt2);
			goto yy12;
		default:
			YYSTAGP(context.yyt2);
			goto yy13;
	}
yy12:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's': goto yy14;
		default: goto yy7;
	}
yy13:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy7;
		case ';':
			YYSTAGN(context.yyt1);
			goto yy12;
		default: goto yy13;
	}
yy14:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy5;
		default: goto yy7;
	}
}


 match:
    if(nsu) {
        /* NamespaceUri */
        UA_String nsUri = {(size_t)(body - 1 - nsu), (UA_Byte*)(uintptr_t)nsu};
        UA_StatusCode res = escapedUri2Index(nsUri, &id->namespaceIndex, nsMapping);
        if(res != UA_STATUSCODE_GOOD) {
            /* Return the entire NodeId string s=... */
            UA_String total = {(size_t)((const UA_Byte*)end - begin), begin};
            id->identifierType = UA_NODEIDTYPE_STRING;
            return UA_String_copy(&total, &id->identifier.string);
        }
    } else if(ns) {
        /* NamespaceIndex */
        UA_UInt32 tmp;
        size_t len = (size_t)(body - 1 - ns);
        if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len)
            return UA_STATUSCODE_BADDECODINGERROR;
        id->namespaceIndex = (UA_UInt16)tmp;
        if(nsMapping)
            id->namespaceIndex =
                UA_NamespaceMapping_remote2Local(nsMapping, id->namespaceIndex);
    }

    /* From the current position until the end */
    return parse_nodeid_body(id, body, end, idEsc);
}

UA_StatusCode
UA_NodeId_parseEx(UA_NodeId *id, const UA_String str,
                  const UA_NamespaceMapping *nsMapping) {
    UA_StatusCode res =
        parse_nodeid(id, str.data, str.data+str.length, UA_ESCAPING_NONE, nsMapping);
    if(res != UA_STATUSCODE_GOOD)
        UA_NodeId_clear(id);
    return res;
}

UA_StatusCode
UA_NodeId_parse(UA_NodeId *id, const UA_String str) {
    return UA_NodeId_parseEx(id, str, NULL);
}

static UA_StatusCode
parse_expandednodeid(UA_ExpandedNodeId *id, const u8 *pos, const u8 *end,
                     UA_Escaping idEsc, const UA_NamespaceMapping *nsMapping,
                     size_t serverUrisSize, const UA_String *serverUris) {
    *id = UA_EXPANDEDNODEID_NULL; /* Reset the NodeId */
    LexContext context;
    memset(&context, 0, sizeof(LexContext));
    const u8 *svr = NULL, *sve = NULL, *svu = NULL,
        *nsu = NULL, *ns = NULL, *body = NULL, *begin = pos;

    
{
	u8 yych;
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			YYSTAGN(context.yyt3);
			YYSTAGN(context.yyt4);
			YYSTAGN(context.yyt5);
			goto yy18;
		case 'n':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			YYSTAGN(context.yyt5);
			goto yy19;
		case 's':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			YYSTAGN(context.yyt3);
			YYSTAGN(context.yyt4);
			YYSTAGN(context.yyt5);
			goto yy20;
		default: goto yy16;
	}
yy16:
	YYSKIP();
yy17:
	{ (void)pos; return UA_STATUSCODE_BADDECODINGERROR; }
yy18:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy21;
		default: goto yy17;
	}
yy19:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 's': goto yy22;
		default: goto yy17;
	}
yy20:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy21;
		case 'v': goto yy24;
		default: goto yy17;
	}
yy21:
	YYSKIP();
	svr = context.yyt5;
	svu = context.yyt1;
	sve = context.yyt2;
	ns = context.yyt3;
	nsu = context.yyt4;
	YYSTAGP(body);
	YYSHIFTSTAG(body, -2);
	{ goto match; }
yy22:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy25;
		case 'u': goto yy26;
		default: goto yy23;
	}
yy23:
	YYRESTORE();
	goto yy17;
yy24:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'r': goto yy27;
		case 'u': goto yy28;
		default: goto yy23;
	}
yy25:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(context.yyt3);
			goto yy29;
		default: goto yy23;
	}
yy26:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy30;
		default: goto yy23;
	}
yy27:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy31;
		default: goto yy23;
	}
yy28:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy32;
		default: goto yy23;
	}
yy29:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy29;
		case ';':
			YYSTAGN(context.yyt4);
			goto yy33;
		default: goto yy23;
	}
yy30:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy23;
		case ';':
			YYSTAGN(context.yyt3);
			YYSTAGP(context.yyt4);
			goto yy33;
		default:
			YYSTAGP(context.yyt4);
			goto yy34;
	}
yy31:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(context.yyt5);
			goto yy35;
		default: goto yy23;
	}
yy32:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy23;
		case ';':
			YYSTAGP(context.yyt1);
			YYSTAGP(context.yyt2);
			YYSTAGN(context.yyt5);
			goto yy37;
		default:
			YYSTAGP(context.yyt1);
			goto yy36;
	}
yy33:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's': goto yy38;
		default: goto yy23;
	}
yy34:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy23;
		case ';':
			YYSTAGN(context.yyt3);
			goto yy33;
		default: goto yy34;
	}
yy35:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy35;
		case ';':
			YYSTAGN(context.yyt1);
			YYSTAGP(context.yyt2);
			goto yy37;
		default: goto yy23;
	}
yy36:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy23;
		case ';':
			YYSTAGP(context.yyt2);
			YYSTAGN(context.yyt5);
			goto yy37;
		default: goto yy36;
	}
yy37:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's':
			YYSTAGN(context.yyt3);
			YYSTAGN(context.yyt4);
			goto yy38;
		case 'n': goto yy39;
		default: goto yy23;
	}
yy38:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy21;
		default: goto yy23;
	}
yy39:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 's': goto yy22;
		default: goto yy23;
	}
}


 match:
    if(svu) {
        /* ServerUri */
        UA_String serverUri = {(size_t)(sve - svu), (UA_Byte*)(uintptr_t)svu};
        size_t i = 0;
        for(; i < serverUrisSize; i++) {
            if(UA_String_equal(&serverUri, &serverUris[i]))
                break;
        }
        if(i == serverUrisSize) {
            /* The ServerUri cannot be mapped. Return the entire input as a
             * string NodeId. */
            UA_String total = {(size_t)(end - begin), (UA_Byte*)(uintptr_t)begin};
            id->nodeId.identifierType = UA_NODEIDTYPE_STRING;
            return UA_String_copy(&total, &id->nodeId.identifier.string);
        }
        id->serverIndex = (UA_UInt32)i;
    } else if(svr) {
        /* ServerIndex */
        size_t len = (size_t)(sve - svr);
        if(UA_readNumber((const UA_Byte*)svr, len, &id->serverIndex) != len)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    if(nsu) {
        /* NamespaceUri */
        UA_String nsuri = {(size_t)(body - 1 - nsu), (UA_Byte*)(uintptr_t)nsu};
        UA_StatusCode res = UA_STATUSCODE_BADDECODINGERROR;
        /* Try to map the NamespaceUri to its NamespaceIndex for ServerIndex == 0.
         * If this fails, keep the full NamespaceUri. */
        if(id->serverIndex == 0)
            res = escapedUri2Index(nsuri, &id->nodeId.namespaceIndex, nsMapping);
        if(res != UA_STATUSCODE_GOOD)
            res = UA_String_copy(&nsuri, &id->namespaceUri); /* Keep the Uri without mapping */
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else if(ns) {
        /* NamespaceIndex */
        UA_UInt32 tmp;
        size_t len = (size_t)(body - 1 - ns);
        if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len)
            return UA_STATUSCODE_BADDECODINGERROR;
        id->nodeId.namespaceIndex = (UA_UInt16)tmp;
        if(nsMapping)
            id->nodeId.namespaceIndex =
                UA_NamespaceMapping_remote2Local(nsMapping, id->nodeId.namespaceIndex);
    }

    /* From the current position until the end */
    return parse_nodeid_body(&id->nodeId, body, end, idEsc);
}

UA_StatusCode
UA_ExpandedNodeId_parseEx(UA_ExpandedNodeId *id, const UA_String str,
                          const UA_NamespaceMapping *nsMapping,
                          size_t serverUrisSize, const UA_String *serverUris) {
    UA_StatusCode res =
        parse_expandednodeid(id, str.data, str.data + str.length, UA_ESCAPING_NONE,
                             nsMapping, serverUrisSize, serverUris);
    if(res != UA_STATUSCODE_GOOD)
        UA_ExpandedNodeId_clear(id);
    return res;
}

UA_StatusCode
UA_ExpandedNodeId_parse(UA_ExpandedNodeId *id, const UA_String str) {
    return UA_ExpandedNodeId_parseEx(id, str, NULL, 0, NULL);
}

static UA_StatusCode
relativepath_addelem(UA_RelativePath *rp, UA_RelativePathElement *el) {
    /* Check for unrealistic path lengths */
    if(rp->elementsSize >= UA_MAXPATHLENGTH)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Allocate memory */
    UA_RelativePathElement *newArray = (UA_RelativePathElement*)
        UA_realloc(rp->elements, sizeof(UA_RelativePathElement) * (rp->elementsSize + 1));
    if(!newArray)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rp->elements = newArray;

    /* Move to the target */
    rp->elements[rp->elementsSize] = *el;
    rp->elementsSize++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parse_qn(UA_QualifiedName *qn, const u8 *pos, const u8 *end,
         UA_Escaping escName, const UA_NamespaceMapping *nsMapping,
         UA_UInt16 defaultNamespaceIndex) {
    size_t len;
    UA_UInt32 tmp;
    UA_String str;
    UA_StatusCode res;

    LexContext context;
    memset(&context, 0, sizeof(LexContext));

    const u8 *begin = pos;
    UA_QualifiedName_init(qn);
    qn->namespaceIndex = defaultNamespaceIndex;

    
{
	u8 yych;
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case ';': goto yy41;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy44;
		default: goto yy43;
	}
yy41:
	YYSKIP();
yy42:
	{ pos = begin; goto match_name; }
yy43:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	if (yych <= 0x00) goto yy42;
	goto yy46;
yy44:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy50;
		default: goto yy42;
	}
yy45:
	YYSKIP();
	yych = YYPEEK();
yy46:
	switch (yych) {
		case 0x00: goto yy47;
		case ';': goto yy48;
		default: goto yy45;
	}
yy47:
	YYRESTORE();
	goto yy42;
yy48:
	YYSKIP();
	{ goto match_uri; }
yy49:
	YYSKIP();
	yych = YYPEEK();
yy50:
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy49;
		case ':': goto yy51;
		default: goto yy47;
	}
yy51:
	YYSKIP();
	{ goto match_index; }
}


 match_index:
    len = (size_t)(pos - 1 - begin);
    if(UA_readNumber((const UA_Byte*)begin, len, &tmp) != len)
        return UA_STATUSCODE_BADDECODINGERROR;
    qn->namespaceIndex = (UA_UInt16)tmp;
    goto match_name;

 match_uri:
    str.length = (size_t)(pos - 1 - begin);
    str.data = (UA_Byte*)(uintptr_t)begin;
    res = escapedUri2Index(str, &qn->namespaceIndex, nsMapping);
    if(res != UA_STATUSCODE_GOOD)
        pos = begin; /* Use the entire string for the name */

 match_name:
    str.length = (size_t)(end - pos);
    str.data = (UA_Byte*)(uintptr_t)pos;
    res = UA_String_copy(&str, &qn->name);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        res = UA_String_unescape(&qn->name, false, escName);
    return res;
}

UA_StatusCode
UA_QualifiedName_parseEx(UA_QualifiedName *qn, const UA_String str,
                         const UA_NamespaceMapping *nsMapping) {
    const u8 *pos = str.data;
    const u8 *end = str.data + str.length;
    UA_StatusCode res = parse_qn(qn, pos, end, UA_ESCAPING_NONE, nsMapping, 0);
    if(res != UA_STATUSCODE_GOOD)
        UA_QualifiedName_clear(qn);
    return res;
}

UA_StatusCode
UA_QualifiedName_parse(UA_QualifiedName *qn, const UA_String str) {
    return UA_QualifiedName_parseEx(qn, str, NULL);
}

/* Add one element to the path in every iteration */
static UA_StatusCode
parse_relativepathElement(UA_RelativePath *rp, const u8 **ppos, const u8 *end,
                          UA_Server *server, UA_Escaping esc,
                          UA_UInt16 defaultTargetNamespaceIndex, UA_Boolean *done) {
    const u8 *pos = *ppos;
    if(pos == end) {
        *done = true;
        return UA_STATUSCODE_GOOD;
    }

    /* Create the element on the stack.
     * Moved into the rp upon successful parsing. */
    UA_RelativePathElement current;
    UA_RelativePathElement_init(&current);
    current.includeSubtypes = true; /* Follow subtypes by default */

    /* Which ReferenceType? */
    const u8 *begin;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(*pos) {
    case '/':
        current.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
        goto reftype_target;
    case '.':
        /* Recognize the dot only for the and-escaping. The dot is not escaped
         * for percent-escaping and commonly used as part of the browse-name. */
        if(esc != UA_ESCAPING_AND) {
            *done = true;
            goto out;
        }
        current.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
        goto reftype_target;
    case '<':
        break;
    default:
        *done = true;
        goto out;
    }

    /* ReferenceType with modifiers wrapped in angle brackets */
    begin = ++pos;
    for(; pos < end; pos++) {
        if((esc == UA_ESCAPING_AND || esc == UA_ESCAPING_AND_EXTENDED) && *pos == '&') {
            pos++;
            continue;
        }
        if((esc == UA_ESCAPING_PERCENT || esc == UA_ESCAPING_PERCENT_EXTENDED) && *pos == '%') {
            pos += 2;
            continue;
        }
        if(*pos == '>')
            break;
    }
    if(pos > end) {
        res = UA_STATUSCODE_BADDECODINGERROR;
        goto out;
    }

    /* Process modifiers */
    for(; begin < pos; begin++) {
        if(*begin == '#')
            current.includeSubtypes = false;
        else if(*begin == '!')
            current.isInverse = true;
        else
            break;
    }

    /* Try to parse a NodeId for the ReferenceType (non-standard!) */
    res = parse_nodeid(&current.referenceTypeId, begin, pos, esc, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        /* Parse the the ReferenceType from its BrowseName (default) */
        UA_QualifiedName refqn;
        res = parse_qn(&refqn, begin, pos, esc, NULL, defaultTargetNamespaceIndex);
        res |= lookupRefType(server, &refqn, &current.referenceTypeId);
        UA_QualifiedName_clear(&refqn);
        if(res != UA_STATUSCODE_GOOD)
            goto out;
    }

 reftype_target:
    /* Move pos to the end of the TargetName based on the escaping */
    begin = ++pos;
    while(pos < end && *pos >= '0' && *pos <= '9')
        pos++;
    if(pos < end && *pos == ':')
        pos++;
    for(; pos < end; pos++) {
        if((esc == UA_ESCAPING_AND || esc == UA_ESCAPING_AND_EXTENDED) && *pos == '&') {
            pos++;
            continue;
        }
        if((esc == UA_ESCAPING_PERCENT || esc == UA_ESCAPING_PERCENT_EXTENDED) && *pos == '%') {
            pos += 2;
            continue;
        }
        if(esc == UA_ESCAPING_PERCENT || esc == UA_ESCAPING_PERCENT_EXTENDED) {
            if(isReservedPercentExtended(*pos))
                break;
        } else {
            if(isReservedAnd(*pos))
                break;
        }
    }
    if(pos > end) {
        res = UA_STATUSCODE_BADDECODINGERROR;
        goto out;
    }

    /* Parse the TargetName */
    res = parse_qn(&current.targetName, begin, pos, esc,
                   NULL, defaultTargetNamespaceIndex);
    if(res != UA_STATUSCODE_GOOD) {
        UA_RelativePathElement_clear(&current);
        goto out;
    }

    /* Add current to the rp */
    res |= relativepath_addelem(rp, &current);

 out:
    if(res != UA_STATUSCODE_GOOD)
        UA_RelativePathElement_clear(&current);

    /* Return the status */
    *ppos = pos;
    *done |= (res != UA_STATUSCODE_GOOD);
    return res;
}

static UA_StatusCode
parse_relativepath(UA_RelativePath *rp, const u8 **ppos, const u8 *end,
                   UA_Server *server, UA_Escaping esc,
                   UA_UInt16 defaultNamespaceIndex) {
    UA_RelativePath_init(rp);
    UA_Boolean done = false;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    do {
        res = parse_relativepathElement(rp, ppos, end, server, esc,
                                        defaultNamespaceIndex, &done);
    } while(!done);
    return res;
}

UA_StatusCode
UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str) {
    const u8 *pos = str.data;
    const u8 *end = pos + str.length;
    UA_StatusCode res = parse_relativepath(rp, &pos, end, NULL, UA_ESCAPING_AND, 0);
    if(pos != end)
        res = UA_STATUSCODE_BADDECODINGERROR;
    if(res != UA_STATUSCODE_GOOD)
        UA_RelativePath_clear(rp);
    return res;
}

UA_StatusCode
UA_RelativePath_parseWithServer(UA_Server *server, UA_RelativePath *rp,
                                const UA_String str) {
    const u8 *pos = str.data;
    const u8 *end = pos + str.length;
    UA_StatusCode res = parse_relativepath(rp, &pos, end, server, UA_ESCAPING_AND, 0);
    if(pos != end)
        res = UA_STATUSCODE_BADDECODINGERROR;
    if(res != UA_STATUSCODE_GOOD)
        UA_RelativePath_clear(rp);
    return res;
}

/* Always uses the percent-escaping. The default namespace-index gets used for
 * the browse path when the namespace of the elements is not given explicitly.
 * This is used for parsing an expression from a QualifiedName that then defines
 * the default namespace-index (cf. the Event-field key-value map). */
#ifdef UA_TYPES_ATTRIBUTEOPERAND
static UA_StatusCode
parseAttributeOperand(UA_AttributeOperand *ao, const UA_String str,
                      UA_NodeId defaultId, UA_UInt16 defaultNamespaceIndex) {
    /* Initialize and set the default values */
    UA_AttributeOperand_init(ao);
    ao->nodeId = defaultId;
    ao->attributeId = UA_ATTRIBUTEID_VALUE;

    /* Nothing to parse */
    if(str.length == 0)
        return UA_STATUSCODE_GOOD;

    const u8 *pos = str.data;
    const u8 *end = pos + str.length;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Initial NodeId before the BrowsePath */
    LexContext context;
    memset(&context, 0, sizeof(LexContext));
    
{
	u8 yych;
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's': goto yy55;
		case 'n': goto yy56;
		default: goto yy53;
	}
yy53:
	YYSKIP();
yy54:
	{ pos = str.data; goto parse_path; }
yy55:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy57;
		default: goto yy54;
	}
yy56:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 's': goto yy58;
		default: goto yy54;
	}
yy57:
	YYSKIP();
	{
        // Find the end position of the NodeId body and parse
        for(; pos < end; pos++) {
            if(*pos == '%') {
                pos += 2;
                continue;
            }
            if(isReservedPercentExtended(*pos))
                break;
        }
        if(pos > end) {
            res = UA_STATUSCODE_BADDECODINGERROR;
            goto cleanup;
        }
        res = parse_nodeid(&ao->nodeId, str.data, pos, UA_ESCAPING_PERCENT, NULL);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
        goto parse_path;
    }
yy58:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy60;
		case 'u': goto yy61;
		default: goto yy59;
	}
yy59:
	YYRESTORE();
	goto yy54;
yy60:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy62;
		default: goto yy59;
	}
yy61:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy63;
		default: goto yy59;
	}
yy62:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy62;
		case ';': goto yy64;
		default: goto yy59;
	}
yy63:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy59;
		case ';': goto yy64;
		default: goto yy63;
	}
yy64:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's': goto yy65;
		default: goto yy59;
	}
yy65:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy57;
		default: goto yy59;
	}
}


    /* Parse the BrowsePath */
 parse_path:
    res = parse_relativepath(&ao->browsePath, &pos, end, NULL,
                             UA_ESCAPING_PERCENT_EXTENDED, defaultNamespaceIndex);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Parse the AttributeId */
    if(pos < end && *pos == '#') {
        const u8 *attr_pos = ++pos;
        while(pos < end && ((*pos >= 'a' && *pos <= 'z') ||
                            (*pos >= 'A' && *pos <= 'Z'))) {
            pos++;
        }
        UA_String attrString = {(size_t)(pos - attr_pos), (UA_Byte*)(uintptr_t)attr_pos};
        ao->attributeId = UA_AttributeId_fromName(attrString);
        if(ao->attributeId == UA_ATTRIBUTEID_INVALID) {
            res = UA_STATUSCODE_BADDECODINGERROR;
            goto cleanup;
        }
    }

    /* Parse the IndexRange */
    if(pos < end && *pos == '[') {
        const u8 *range_pos = ++pos;
        while(pos < end && *pos != ']') {
            pos++;
        }
        if(pos == end) {
            res = UA_STATUSCODE_BADDECODINGERROR;
            goto cleanup;
        }
        UA_String rangeString = {(size_t)(pos - range_pos), (UA_Byte*)(uintptr_t)range_pos};
        if(rangeString.length > 0)
            res = UA_String_copy(&rangeString, &ao->indexRange);
        pos++;
    }

    /* Check that we have parsed the entire string */
    if(pos != end)
        res = UA_STATUSCODE_BADDECODINGERROR;


 cleanup:
    if(res != UA_STATUSCODE_GOOD)
        UA_AttributeOperand_clear(ao);
    return res;
}

UA_StatusCode
UA_AttributeOperand_parse(UA_AttributeOperand *ao, const UA_String str) {
    /* Objects folder is the default */
    return parseAttributeOperand(ao, str, UA_NS0ID(OBJECTSFOLDER), 0);
}

UA_StatusCode
sao_parseWithDefaultNsIdx(UA_SimpleAttributeOperand *sao,
                          const UA_String str, UA_UInt16 defaultNsIndex) {
    /* Parse an AttributeOperand and convert */
    UA_AttributeOperand ao;
    const UA_NodeId hierarchRefs = UA_NS0ID(HIERARCHICALREFERENCES);
    UA_StatusCode res =
        parseAttributeOperand(&ao, str, UA_NS0ID(BASEEVENTTYPE), defaultNsIndex);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Initialize the sao and copy over */
    UA_SimpleAttributeOperand_init(sao);
    sao->attributeId = ao.attributeId;
    sao->indexRange = ao.indexRange;
    UA_String_init(&ao.indexRange);
    sao->typeDefinitionId = ao.nodeId;
    UA_NodeId_init(&ao.nodeId);

    if(ao.browsePath.elementsSize > 0) {
        sao->browsePath = (UA_QualifiedName *)
            UA_calloc(ao.browsePath.elementsSize, sizeof(UA_QualifiedName));
        if(!sao->browsePath) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
            goto cleanup;
        }
        sao->browsePathSize = ao.browsePath.elementsSize;
    }

    for(size_t i = 0; i < ao.browsePath.elementsSize; i++) {
        UA_RelativePathElement *e = &ao.browsePath.elements[i];

        /* Must use hierarchical references (/) */
        if(!UA_NodeId_equal(&e->referenceTypeId, &hierarchRefs)) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
            goto cleanup;
        }

        /* Includes subtypes and not inverse */
        if(!e->includeSubtypes || e->isInverse) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
            goto cleanup;
        }

        sao->browsePath[i] = e->targetName;
        UA_QualifiedName_init(&e->targetName);
    }

 cleanup:
    UA_AttributeOperand_clear(&ao);
    if(res != UA_STATUSCODE_GOOD)
        UA_SimpleAttributeOperand_clear(sao);
    return res;
}

UA_StatusCode
UA_SimpleAttributeOperand_parse(UA_SimpleAttributeOperand *sao,
                                const UA_String str) {
    return sao_parseWithDefaultNsIdx(sao, str, 0);
}

UA_StatusCode
UA_ReadValueId_parse(UA_ReadValueId *rvi, const UA_String str) {
    /* Parse an AttributeOperand and convert */
    UA_AttributeOperand ao;
    UA_StatusCode res = parseAttributeOperand(&ao, str, UA_NODEID_NULL, 0);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    if(ao.browsePath.elementsSize > 0) {
        UA_AttributeOperand_clear(&ao);
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    UA_ReadValueId_init(rvi);
    rvi->nodeId = ao.nodeId;
    rvi->attributeId = ao.attributeId;
    rvi->indexRange = ao.indexRange;
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_TYPES_ATTRIBUTEOPERAND */

/**** amalgamated original file "/src/util/ua_encryptedsecret.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2025 (c) Siemens AG (Author: Tin Raic)
 *    Copyright 2025-2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


/************************/
/* ECC Encrypted Secret */
/************************/

typedef struct {
    /* Common Header */
    UA_NodeId typeId;
    UA_Byte encodingMask;
    UA_UInt32 length;
    UA_String securityPolicyUri;
    UA_ByteString certificate;
    UA_DateTime signingTime;
    UA_UInt16 keyDataLen;

    /* Policy Header*/
    UA_ByteString senderPublicKey;
    UA_ByteString receiverPublicKey;

    /* Payload */
    UA_ByteString nonce;
    UA_ByteString secret;
    /* UA_ByteString padding; // Computed when needed */

    /* Signature */
    UA_Byte* signature;
} UA_EccEncryptedSecretStruct;

static void
UA_EccEncryptedSecretStruct_init(UA_EccEncryptedSecretStruct* es) {
    memset(es, 0, sizeof(UA_EccEncryptedSecretStruct));
}

static void
UA_EccEncryptedSecretStruct_clear(UA_EccEncryptedSecretStruct* es) {
    UA_String_clear(&es->securityPolicyUri);
    UA_ByteString_clear(&es->certificate);
    UA_ByteString_clear(&es->senderPublicKey);
    UA_ByteString_clear(&es->receiverPublicKey);
    UA_ByteString_clear(&es->nonce);
    UA_ByteString_clear(&es->secret);
    UA_EccEncryptedSecretStruct_init(es);
}

static size_t
UA_EccEncryptedSecret_getCommonHeaderSize(const UA_EccEncryptedSecretStruct* src) {
    size_t len = 0;
    len += UA_calcSizeBinary(&src->typeId, &UA_TYPES[UA_TYPES_NODEID], NULL);
    len += UA_calcSizeBinary(&src->encodingMask, &UA_TYPES[UA_TYPES_BYTE], NULL);
    len += UA_calcSizeBinary(&src->length, &UA_TYPES[UA_TYPES_UINT32], NULL);
    len += UA_calcSizeBinary(&src->securityPolicyUri, &UA_TYPES[UA_TYPES_STRING], NULL);
    len += UA_calcSizeBinary(&src->certificate, &UA_TYPES[UA_TYPES_BYTESTRING], NULL);
    len += UA_calcSizeBinary(&src->signingTime, &UA_TYPES[UA_TYPES_DATETIME], NULL);
    len += UA_calcSizeBinary(&src->keyDataLen, &UA_TYPES[UA_TYPES_UINT16], NULL);
    return len;
}

static size_t
UA_EccEncryptedSecret_getPolicyHeaderSize(const UA_EccEncryptedSecretStruct* src) {
    size_t len = 0;
    len += UA_calcSizeBinary(&src->senderPublicKey, &UA_TYPES[UA_TYPES_BYTESTRING], NULL);
    len += UA_calcSizeBinary(&src->receiverPublicKey, &UA_TYPES[UA_TYPES_BYTESTRING], NULL);
    return len;
}

static UA_StatusCode
UA_EccEncryptedSecret_serializeCommonHeader(const UA_EccEncryptedSecretStruct *src,
                                            UA_Byte** bufPos, const UA_Byte* bufEnd) {
    UA_UInt32 length32 = (UA_UInt32)src->length;
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    ret |= UA_NodeId_encodeBinary(&src->typeId, bufPos, bufEnd);
    ret |= UA_Byte_encodeBinary(&src->encodingMask, bufPos, bufEnd);
    ret |= UA_UInt32_encodeBinary(&length32, bufPos, bufEnd);
    ret |= UA_String_encodeBinary(&src->securityPolicyUri, bufPos, bufEnd);
    ret |= UA_ByteString_encodeBinary(&src->certificate, bufPos, bufEnd);
    ret |= UA_DateTime_encodeBinary(&src->signingTime, bufPos, bufEnd);
    ret |= UA_UInt16_encodeBinary(&src->keyDataLen, bufPos, bufEnd);
    return ret;
}

static UA_StatusCode
UA_EccEncryptedSecret_serializePolicyHeader(const UA_EccEncryptedSecretStruct *src,
                                            UA_Byte** bufPos, const UA_Byte* bufEnd) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    ret |= UA_ByteString_encodeBinary(&src->senderPublicKey, bufPos, bufEnd);
    ret |= UA_ByteString_encodeBinary(&src->receiverPublicKey, bufPos, bufEnd);
    return ret;
}

static UA_StatusCode
UA_EccEncryptedSecret_deserializeCommonHeader(UA_EccEncryptedSecret *src,
                                              UA_EccEncryptedSecretStruct *dest,
                                              size_t* offset) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    ret |= UA_NodeId_decodeBinary(src, offset, &dest->typeId);
    ret |= UA_Byte_decodeBinary(src, offset, &dest->encodingMask);
    ret |= UA_UInt32_decodeBinary(src, offset, &dest->length);
    ret |= UA_String_decodeBinary(src, offset, &dest->securityPolicyUri);
    ret |= UA_ByteString_decodeBinary(src, offset, &dest->certificate);
    ret |= UA_DateTime_decodeBinary(src, offset, &dest->signingTime);
    ret |= UA_UInt16_decodeBinary(src, offset, &dest->keyDataLen);
    return ret;
}

static UA_StatusCode
UA_EccEncryptedSecret_deserializePolicyHeader(UA_EccEncryptedSecret *src,
                                              UA_EccEncryptedSecretStruct *dest,
                                              size_t* offset) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    ret |= UA_ByteString_decodeBinary(src, offset, &dest->senderPublicKey);
    ret |= UA_ByteString_decodeBinary(src, offset, &dest->receiverPublicKey);
    return ret;
}

UA_StatusCode
encryptUserIdentityTokenEcc(UA_Logger *logger, UA_SecureChannel *channel,
                            const UA_SecurityPolicy *sp, void *spContext,
                            UA_ByteString *tokenData,
                            const UA_ByteString serverSessionNonce,
                            const UA_ByteString serverEphemeralPubKey) {
    /* Extract some basic information from the SecurityPolicy. AEAD policies
     * (AES-GCM) expose a dedicated IV length (12 bytes) and append an
     * authentication tag after the ciphertext; legacy CBC policies use the
     * cipher block size as the IV length and have no tag. */
    UA_Boolean aead = UA_SecurityPolicy_isAead(sp);
    size_t symKeyLen = sp->symEncryptionAlgorithm.getLocalKeyLength(sp, spContext);
    size_t ivLen = (aead && sp->symEncryptionAlgorithm.getLocalIvLength) ?
        sp->symEncryptionAlgorithm.getLocalIvLength(sp, spContext) :
        sp->symEncryptionAlgorithm.getRemoteBlockSize(sp, spContext);
    size_t tagLen = aead ?
        sp->symSignatureAlgorithm.getLocalSignatureSize(sp, spContext) : 0;
    size_t sigLen = sp->asymSignatureAlgorithm.getRemoteSignatureSize(sp, spContext);
    UA_assert(symKeyLen > 0 && ivLen > 0);

    /* Filling out the EccEncryptedSecretStruct fields. The length field is
     * computed after. */
    UA_EccEncryptedSecretStruct secret;
    UA_EccEncryptedSecretStruct_init(&secret);
    secret.typeId = UA_NS0ID(ECCENCRYPTEDSECRET);
    secret.encodingMask = 0x01;
    secret.signingTime = UA_DateTime_now();

    /* Copy-only methods */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    retval |= UA_String_copy(&sp->policyUri, &secret.securityPolicyUri);
    retval |= UA_ByteString_copy(&sp->localCertificate, &secret.certificate);
    retval |= UA_ByteString_copy(&serverEphemeralPubKey, &secret.receiverPublicKey);
    retval |= UA_ByteString_copy(&serverSessionNonce, &secret.nonce);
    retval |= UA_ByteString_copy(tokenData, &secret.secret);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_EccEncryptedSecretStruct_clear(&secret);
        return retval;
    }

    /* Generate a new local ephemeral key. The private part remains persisted
     * inside the SecurityPolicy. */
    size_t ephKeyLen = sp->nonceLength; /* Also length of the ephemeral public key */
    retval = UA_ByteString_allocBuffer(&secret.senderPublicKey, ephKeyLen);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_EccEncryptedSecretStruct_clear(&secret);
        return retval;
    }
    secret.senderPublicKey.data[0] = 'e';
    secret.senderPublicKey.data[1] = 'p';
    secret.senderPublicKey.data[2] = 'h';
    retval = sp->generateNonce(sp, spContext, &secret.senderPublicKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel,
                     "EccEncryptedSecret: Failed to generate local ephemeral key");
        UA_EccEncryptedSecretStruct_clear(&secret);
        return retval;
    }

    /* Compute the padding. the alignment block is 16 bytes for AEAD (AES-GCM)
     * and the IV/block size for CBC. The padding region is `paddingCount` bytes
     * of value paddingCount, followed by a 2-byte padding-size field
     * (PaddingSize | ExtraPaddingSize); those 2 bytes are included in the
     * alignment. */
    size_t blockSize = aead ? 16 : ivLen;
    size_t baseLen = UA_ByteString_calcSizeBinary(&secret.nonce) +
                     UA_ByteString_calcSizeBinary(&secret.secret);
    size_t modLen = (baseLen + 2) % blockSize;
    size_t paddingCount = (modLen == 0) ? 0 : (blockSize - modLen);
    if(paddingCount + secret.secret.length < blockSize)
        paddingCount += blockSize;
    size_t encryptedLength = baseLen + paddingCount + 2;

    /* Compute the total length including the headers and the signature */
    size_t signatureLen = sp->asymSignatureAlgorithm.
        getLocalSignatureSize(sp, spContext);
    secret.keyDataLen = (UA_UInt16)
        UA_EccEncryptedSecret_getPolicyHeaderSize(&secret);
    size_t totalLength = encryptedLength + tagLen + secret.keyDataLen +
        UA_EccEncryptedSecret_getCommonHeaderSize(&secret) + signatureLen;

    /* The EncryptedSecret "Length" field is the number of bytes that FOLLOW the
     * Length field, not the full serialized size. Subtract the common-header
     * prefix (TypeId NodeId + EncodingByte + the Length field itself = 9
     * bytes). */
    size_t headerPrefix =
        UA_calcSizeBinary(&secret.typeId, &UA_TYPES[UA_TYPES_NODEID], NULL) +
        UA_calcSizeBinary(&secret.encodingMask, &UA_TYPES[UA_TYPES_BYTE], NULL) +
        UA_calcSizeBinary(&secret.length, &UA_TYPES[UA_TYPES_UINT32], NULL);
    secret.length = (UA_UInt32)(totalLength - headerPrefix);

    /* Compute the symmetric key to encrypt */
    UA_ByteString symEncKeyMaterial;
    retval = UA_ByteString_allocBuffer(&symEncKeyMaterial, symKeyLen+ivLen);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_EccEncryptedSecretStruct_clear(&secret);
        return retval;
    }

    /* This is a (temporary) measure so that the salt generation function (for
     * the symmetric key derivation ) knows that the salt is generated for
     * session authentication (to choose the correct label) */
    /* TODO: find a better way to signal symmetric key generation for session
     * authentication */
    symEncKeyMaterial.data[0] = 0x03;
    symEncKeyMaterial.data[1] = 0x03;
    symEncKeyMaterial.data[2] = 0x04;
    retval = sp->generateKey(sp, spContext, &secret.receiverPublicKey,
                             &secret.senderPublicKey, &symEncKeyMaterial);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel,
                             "EccEncryptedSecret: Failed to derive key material");
        UA_ByteString_clear(&symEncKeyMaterial);
        UA_EccEncryptedSecretStruct_clear(&secret);
        return retval;
    }

    /* Extracting the key and the initialization vector from the key material */
    UA_ByteString encKey = {symKeyLen, symEncKeyMaterial.data};
    UA_ByteString iv = {ivLen, &symEncKeyMaterial.data[symKeyLen]};
    retval |= sp->setLocalSymEncryptingKey(sp, spContext, &encKey);
    retval |= sp->setLocalSymIv(sp, spContext, &iv);
    UA_ByteString_clear(&symEncKeyMaterial);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel,
                             "EccEncryptedSecret: Failed to set EncryptingKey/"
                             "IV in the SecurityPolicy");
        UA_EccEncryptedSecretStruct_clear(&secret);
        return retval;
    }

    /* Allocate the output buffer */
    UA_ByteString output;
    retval = UA_ByteString_allocBuffer(&output, totalLength);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_EccEncryptedSecretStruct_clear(&secret);
        return retval;
    }

    /* Encode all the content into the output buffer */
    UA_Byte* bufPos = output.data;
    UA_Byte* bufEnd = output.data + output.length;
    retval |= UA_EccEncryptedSecret_serializeCommonHeader(&secret, &bufPos, bufEnd);
    retval |= UA_EccEncryptedSecret_serializePolicyHeader(&secret, &bufPos, bufEnd);
    UA_Byte* payloadPos = bufPos;
    retval |= UA_ByteString_encodeBinary(&secret.nonce, &bufPos, bufEnd);
    retval |= UA_ByteString_encodeBinary(&secret.secret, &bufPos, bufEnd);
    UA_Byte pad = (UA_Byte)(paddingCount & 0xFF);
    for(size_t i = 0; i < paddingCount; i++) {
        *bufPos = pad;
        bufPos++;
    }
    /* 2-byte padding-size field: PaddingSize byte + ExtraPaddingSize byte.
     * For paddingCount < 256 this equals the little-endian UInt16. */
    UA_UInt16 paddingCount16 = (UA_UInt16)paddingCount;
    retval |= UA_UInt16_encodeBinary(&paddingCount16, &bufPos, bufEnd);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_EccEncryptedSecretStruct_clear(&secret);
        UA_ByteString_clear(&output);
        return retval;
    }

    /* Encrypt the payload region in-situ. For AEAD (AES-GCM) the GCM primitive
     * writes the authentication tag into the last `tagLen` bytes of the buffer
     * it is given, so the region passed in spans the plaintext plus the
     * reserved tag bytes. The AAD is the EccEncryptedSecret header preceding
     * the encrypted region, and the IV is used unmasked (tokenId / sequence
     * number = 0). */
    UA_ByteString payload = {(size_t)(bufPos - payloadPos) + tagLen, payloadPos};
    if(aead) {
        UA_ByteString aad = {(size_t)(payloadPos - output.data), output.data};
        retval |= sp->setMessageSecurityParameters(sp, spContext, 0, 0, &aad);
    }
    retval |= sp->symEncryptionAlgorithm.encrypt(sp, spContext, &payload);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel,
                     "EccEncryptedSecret: Failed to encrypt the payload");
        UA_EccEncryptedSecretStruct_clear(&secret);
        UA_ByteString_clear(&output);
        return retval;
    }

    /* The authentication tag (if any) now occupies the next tagLen bytes;
     * advance past it to the signature slot. */
    bufPos += tagLen;
    UA_assert(bufPos + sigLen == bufEnd);

    /* Compute the overall signature over everything except the signature. */
    UA_ByteString sigContent = {(size_t)(bufPos - output.data), output.data};
    UA_ByteString signature = {sigLen, bufPos};
    retval = sp->asymSignatureAlgorithm.sign(sp, spContext, &sigContent, &signature);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel,
                     "EccEncryptedSecret: Failed to sign the EccEncryptedSecret");
        UA_EccEncryptedSecretStruct_clear(&secret);
        UA_ByteString_clear(&output);
        return retval;
    }

    /* Replace tokenData with the output */
    UA_ByteString_clear(tokenData);
    *tokenData = output;

    UA_EccEncryptedSecretStruct_clear(&secret);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
decryptUserTokenEcc(UA_Logger *logger, UA_SecureChannel *channel,
                    const UA_SecurityPolicy *sp, void *spContext,
                    UA_ByteString sessionServerNonce,
                    UA_EccEncryptedSecret *es) {
    /* ECC usage verified before calling into this function */
    UA_assert(UA_SecurityPolicy_isEcc(sp));

    /* Define and initialize in case of clean-up */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_EccEncryptedSecretStruct esd;
    UA_EccEncryptedSecretStruct_init(&esd);
    UA_ByteString symEncKeyMaterial = UA_BYTESTRING_NULL;
    UA_ByteString pass = UA_BYTESTRING_NULL;

    size_t offset = 0;
    res = UA_EccEncryptedSecret_deserializeCommonHeader(es, &esd, &offset);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Failed to decode the common header");
        goto cleanecc;
    }

    /* Check TypeId */
    UA_NodeId eccTypeId = UA_NS0ID(ECCENCRYPTEDSECRET);
    if(!UA_NodeId_equal(&eccTypeId, &esd.typeId) ||
       esd.encodingMask != 0x01 ||
       !UA_String_equal(&esd.securityPolicyUri, &sp->policyUri)) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Inconsistent common header");
        res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto cleanecc;
    }

    /* The "Length" field counts the bytes following the Length field, so the
     * end of the secret is (Length + the common-header prefix: TypeId NodeId +
     * EncodingByte + Length field). Validate it and use it (instead of the
     * whole ByteString size) for the payload/signature bounds. */
    size_t headerPrefix =
        UA_calcSizeBinary(&esd.typeId, &UA_TYPES[UA_TYPES_NODEID], NULL) +
        UA_calcSizeBinary(&esd.encodingMask, &UA_TYPES[UA_TYPES_BYTE], NULL) +
        UA_calcSizeBinary(&esd.length, &UA_TYPES[UA_TYPES_UINT32], NULL);
    size_t endOfSecret = (size_t)esd.length + headerPrefix;
    if(endOfSecret > es->length || endOfSecret <= offset) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Inconsistent Length field");
        res = UA_STATUSCODE_BADDECODINGERROR;
        goto cleanecc;
    }

    /* Verify signature */
    size_t sigLen = sp->asymSignatureAlgorithm.getRemoteSignatureSize(sp, spContext);
    size_t signedDataLen = endOfSecret - sigLen;
    UA_ByteString signedData = {signedDataLen, es->data};
    UA_ByteString signature = {sigLen, &es->data[signedDataLen]};
    res = sp->asymSignatureAlgorithm.verify(sp, spContext, &signedData, &signature);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Signature verification failed");
        goto cleanecc;
    }

    size_t oldoffset = offset;
    res = UA_EccEncryptedSecret_deserializePolicyHeader(es, &esd, &offset);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Failed to decode the policy header");
        goto cleanecc;
    }

    /* Sanity check of the key data length.
     * This needs to include the 2x4 byte length fields. */
    if(esd.keyDataLen != (UA_UInt16)(offset - oldoffset)) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Inconstent KeyDataLength");
        res = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        goto cleanecc;
    }

    /* Check the payload length */
    if(endOfSecret <= offset + sigLen) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Inconstent payload / signature length");
        res = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        goto cleanecc;
    }
    UA_ByteString payload = {endOfSecret - offset - sigLen, es->data + offset};

    /* Deriving (remote) symmetric encryption key to decrypt the payload.
     * AEAD policies (AES-GCM) use a dedicated 12-byte IV length; legacy CBC
     * uses the cipher block size. */
    UA_Boolean aead = UA_SecurityPolicy_isAead(sp);
    size_t symKeyLen = sp->symEncryptionAlgorithm.getRemoteKeyLength(sp, spContext);
    size_t ivLen = (aead && sp->symEncryptionAlgorithm.getLocalIvLength) ?
        sp->symEncryptionAlgorithm.getLocalIvLength(sp, spContext) :
        sp->symEncryptionAlgorithm.getRemoteBlockSize(sp, spContext);
    res = UA_ByteString_allocBuffer(&symEncKeyMaterial, symKeyLen+ivLen);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanecc;

    /* This is a (temporary) measure so that the salt generation function (for
     * the symmetric key derivation ) knows that the salt is generated for
     * session authentication (to choose the correct label) */
    /* TODO: find a better way to signal symmetric key generation for session
     * authentication */
    symEncKeyMaterial.data[0] = 0x03;
    symEncKeyMaterial.data[1] = 0x03;
    symEncKeyMaterial.data[2] = 0x04;

    /* Call logic for server for session authentication: receiver public key is
     * local (server), sender public key is remote (client) */
    res = sp->generateKey(sp, spContext, &esd.receiverPublicKey,
                          &esd.senderPublicKey, &symEncKeyMaterial);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Failed to derive key material");
        goto cleanecc;
    }

    /* Extract the encryption key and the initialization vector */
    UA_ByteString encKey = {symKeyLen, symEncKeyMaterial.data};
    UA_ByteString iv = {ivLen, &symEncKeyMaterial.data[symKeyLen]};

    /* Set IV and RemoteEncryptingKey. That is all we need to decode the
     * secret. */
    res |= sp->setRemoteSymEncryptingKey(sp, spContext, &encKey);
    res |= sp->setRemoteSymIv(sp, spContext, &iv);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Failed to set IV/RemoteSymEncryptingKey");
        goto cleanecc;
    }

    /* For AEAD (AES-GCM), the AAD is the EccEncryptedSecret header that
     * precedes the encrypted region and the IV is used unmasked (tokenId /
     * sequence number = 0). The 16-byte tag at the end of the payload is
     * verified (and stripped) by the decrypt. */
    if(aead) {
        UA_ByteString aad = {(size_t)(payload.data - es->data), es->data};
        res = sp->setMessageSecurityParameters(sp, spContext, 0, 0, &aad);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                                 "Failed to set AEAD parameters");
            goto cleanecc;
        }
    }

    /* Decrypt payload (password) */
    res = sp->symEncryptionAlgorithm.decrypt(sp, spContext, &payload);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Failed to decrypt the payload");
        goto cleanecc;
    }

    /* Decode nonce and secret */
    offset = 0; /* Within the payload */
    UA_ByteString nonce;
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    ret |= UA_ByteString_decodeBinary(&payload, &offset, &nonce);
    ret |= UA_ByteString_decodeBinary(&payload, &offset, &pass);
    if(ret != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&nonce);
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Failed to decode the payload");
        goto cleanecc;
    }

    /* Compare the nonce */
    UA_Boolean nonceMatch = UA_ByteString_equal(&sessionServerNonce, &nonce);
    UA_ByteString_clear(&nonce);
    if(!nonceMatch) {
        UA_LOG_ERROR_CHANNEL(logger, channel, "EccEncryptedSecret: "
                             "Nonce does not match");
        res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto cleanecc;
    }

    /* Decode the padding length and validate */
    UA_UInt16 paddingSize = 0;
    size_t paddingOffset = payload.length - 2;
    UA_UInt16_decodeBinary(&payload, &paddingOffset, &paddingSize);
    UA_Byte padd = (UA_Byte)paddingSize;
    for(; offset < payload.length-2; offset++) {
        if(payload.data[offset] != padd) {
            UA_LOG_ERROR_CHANNEL(logger, channel,
                                 "EccEncryptedSecret: Inconsistent padding");
            res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            goto cleanecc;
        }
    }

    /* Copy the password to the output */
    memcpy(es->data, pass.data, pass.length);
    es->length = pass.length;

cleanecc:
    UA_EccEncryptedSecretStruct_clear(&esd);
    UA_ByteString_clear(&symEncKeyMaterial);
    UA_ByteString_clear(&pass);
    return res;
}

/***************************/
/* Legacy Encrypted Secret */
/***************************/

UA_StatusCode
encryptSecretLegacy(const UA_SecurityPolicy *sp, void *spContext,
                    const UA_ByteString serverSessionNonce,
                    UA_ByteString *tokenData) {
    /* Compute the encrypted length (at least one byte padding) */
    size_t plainTextBlockSize = sp->asymEncryptionAlgorithm.
        getRemotePlainTextBlockSize(sp, spContext);
    size_t encryptedBlockSize = sp->asymEncryptionAlgorithm.
        getRemoteBlockSize(sp, spContext);
    UA_UInt32 length =
        (UA_UInt32)(tokenData->length + serverSessionNonce.length);
    UA_UInt32 totalLength = length + 4; /* Including the length field */
    size_t blocks = totalLength / plainTextBlockSize;
    if(totalLength % plainTextBlockSize != 0)
        blocks++;
    size_t encryptedLength = blocks * encryptedBlockSize;

    /* Allocate memory for the encrypted secret */
    UA_ByteString encrypted;
    UA_StatusCode res = UA_ByteString_allocBuffer(&encrypted, encryptedLength);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Copy the secret and the nonce into the output */
    UA_Byte *pos = encrypted.data;
    const UA_Byte *end = &encrypted.data[encrypted.length];
    res = UA_UInt32_encodeBinary(&length, &pos, end);
    memcpy(pos, tokenData->data, tokenData->length);
    memcpy(&pos[tokenData->length], serverSessionNonce.data,
           serverSessionNonce.length);
    UA_assert(res == UA_STATUSCODE_GOOD);

    /* Add padding
     *
     * 7.36.2.2 Legacy Encrypted Token Secret Format: A Client should not add
     * any padding after the secret. If a Client adds padding then all bytes
     * shall be zero. A Server shall check for padding added by Clients and
     * ensure that all padding bytes are zeros. */
    size_t paddedLength = plainTextBlockSize * blocks;
    for(size_t i = totalLength; i < paddedLength; i++)
        encrypted.data[i] = 0;
    encrypted.length = paddedLength;

    /* Encrypt */
    res = sp->asymEncryptionAlgorithm.encrypt(sp, spContext, &encrypted);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&encrypted);
        return res;
    }

    /* Replace the tokenData with the output */
    encrypted.length = encryptedLength;
    UA_ByteString_clear(tokenData);
    *tokenData = encrypted;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
decryptSecretLegacy(const UA_SecurityPolicy *sp, void *spContext,
                    const UA_ByteString serverSessionNonce,
                    UA_ByteString *tokenData) {
    UA_UInt32 secretLen = 0;
    UA_ByteString secret, tokenNonce;
    size_t tokenpos = 0;
    size_t offset = 0;
    const UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;

    /* Decrypt the secret */
    UA_StatusCode res = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
    if(UA_ByteString_copy(tokenData, &secret) != UA_STATUSCODE_GOOD ||
       asymEnc->decrypt(sp, spContext, &secret) != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* The secret starts with a UInt32 length for the content */
    if(UA_UInt32_decodeBinary(&secret, &offset, &secretLen) != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* The decrypted data must be large enough to include the Encrypted Token
     * Secret Format and the length field must indicate enough data to include
     * the server nonce. */
    if(secret.length < sizeof(UA_UInt32) + serverSessionNonce.length ||
       secret.length < sizeof(UA_UInt32) + secretLen ||
       secretLen < serverSessionNonce.length)
        goto cleanup;

    /* If the Encrypted Token Secret contains padding, the padding must be
     * zeroes according to the 1.04.1 specification errata, chapter 3. */
    for(size_t i = sizeof(UA_UInt32) + secretLen; i < secret.length; i++) {
        if(secret.data[i] != 0)
            goto cleanup;
    }

    /* The server nonce must match according to the 1.04.1 specification errata,
     * chapter 3. */
    tokenpos = sizeof(UA_UInt32) + secretLen - serverSessionNonce.length;
    tokenNonce.length = serverSessionNonce.length;
    tokenNonce.data = &secret.data[tokenpos];
    if(!UA_ByteString_equal(&serverSessionNonce, &tokenNonce))
        goto cleanup;

    /* The password was decrypted successfully. Replace usertoken with the
     * decrypted password. The encryptionAlgorithm and policyId fields are left
     * in the UserToken as an indication for the AccessControl plugin that
     * evaluates the decrypted content. */
    size_t outLen = secretLen - serverSessionNonce.length;
    memcpy(tokenData->data, &secret.data[sizeof(UA_UInt32)], outLen);
    tokenData->length = outLen;
    res = UA_STATUSCODE_GOOD;

 cleanup:
    UA_ByteString_clear(&secret);
    return res;
}

/**** amalgamated original file "/src/ua_securechannel.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2016-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018-2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */



#define UA_BITMASK_MESSAGETYPE 0x00ffffffu
#define UA_BITMASK_CHUNKTYPE 0xff000000u

const UA_String UA_SECURITY_POLICY_NONE_URI =
    {47, (UA_Byte *)"http://opcfoundation.org/UA/SecurityPolicy#None"};

void
UA_SecureChannel_init(UA_SecureChannel *channel) {
    /* Normal linked lists are initialized by zeroing out */
    memset(channel, 0, sizeof(UA_SecureChannel));
    TAILQ_INIT(&channel->chunks);
}

UA_StatusCode
UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel, UA_SecurityPolicy *sp,
                                   const UA_ByteString *remoteCertificate) {
    /* Is a policy already configured? */
    UA_CHECK_ERROR(!channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR,
                   sp->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "Security policy already configured");

    /* Create the context */
    UA_StatusCode res = sp->newChannelContext(sp, remoteCertificate,
                                              &channel->channelContext);
    res |= UA_ByteString_copy(remoteCertificate, &channel->remoteCertificate);
    UA_CHECK_STATUS_ERROR(res, return res, sp->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                          "Could not set up the SecureChannel context");

    /* Compute the certificate thumbprint */
    UA_ByteString remoteCertificateThumbprint =
        {20, channel->remoteCertificateThumbprint};
    res = sp->makeCertThumbprint(sp, &channel->remoteCertificate,
                                 &remoteCertificateThumbprint);
    UA_CHECK_STATUS_ERROR(res, return res, sp->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                          "Could not create the certificate thumbprint");

    /* Set the SecurityPolicy and cache the URI-derived properties (the policy
     * is fixed for the channel's lifetime). */
    channel->securityPolicy = sp;
    channel->enhancedSecurity = UA_SecurityPolicy_isEnhancedSecurity(sp);
    channel->legacySequenceNumbers = UA_SecurityPolicy_useLegacySequenceNumbers(sp);

    /* Set a temporary SecurityMode. The client sets the final SecurityMode
     * right after. The server only after fully decoding the OPN message in the
     * OpenSecureChannel service. But we need the SecurityMode for decoding. The
     * OPN message is always signed and encrypted when not #None. */
    if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE)
        channel->securityMode = UA_MESSAGESECURITYMODE_NONE;
    else
        channel->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
    return UA_STATUSCODE_GOOD;
}

/* The #None SecurityPolicy must use the NONE SecurityMode. All other
 * SecurityPolicies must not. */
UA_StatusCode
UA_SecureChannel_setSecurityMode(UA_SecureChannel *channel,
                                 UA_MessageSecurityMode securityMode) {
    if(securityMode == UA_MESSAGESECURITYMODE_INVALID ||
       securityMode > UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_BADSECURITYMODEREJECTED;
    UA_SecurityPolicy *sp = channel->securityPolicy;
    if(!sp)
        return UA_STATUSCODE_BADSECURITYMODEREJECTED;
    UA_Boolean isNonePolicy = (sp->policyType == UA_SECURITYPOLICYTYPE_NONE);
    UA_Boolean isNoneMode = (securityMode == UA_MESSAGESECURITYMODE_NONE);
    if(isNonePolicy != isNoneMode)
        return UA_STATUSCODE_BADSECURITYMODEREJECTED;
    channel->securityMode = securityMode;
    return UA_STATUSCODE_GOOD;
}

/* Hides some errors before sending them to a client according to the
 * standard. */
static void
hideErrors(UA_TcpErrorMessage *const error) {
    switch(error->error) {
    case UA_STATUSCODE_BADCERTIFICATEINVALID:
    case UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE:
    case UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED:
    case UA_STATUSCODE_BADCERTIFICATEUNTRUSTED:
    case UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN:
    case UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN:
    case UA_STATUSCODE_BADCERTIFICATEREVOKED:
    case UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED:
    case UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED:
        error->error = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        error->reason = UA_STRING_NULL;
        break;
        // TODO: Check if these are all cases that need to be covered.
    default:
        break;
    }
}

UA_Boolean
UA_SecureChannel_isConnected(UA_SecureChannel *channel) {
    return (channel->state > UA_SECURECHANNELSTATE_CLOSED &&
            channel->state < UA_SECURECHANNELSTATE_CLOSING);
}

void
UA_SecureChannel_sendERR(UA_SecureChannel *channel, UA_TcpErrorMessage *error) {
    if(!UA_SecureChannel_isConnected(channel))
        return;

    hideErrors(error);

    UA_TcpMessageHeader header;
    header.messageTypeAndChunkType = UA_MESSAGETYPE_ERR + UA_CHUNKTYPE_FINAL;
    /* Header + ErrorMessage (error + reasonLength_field + length) */
    header.messageSize = 8 + (4 + 4 + (UA_UInt32)error->reason.length);

    /* Get the send buffer from the network layer */
    UA_ConnectionManager *cm = channel->connectionManager;
    UA_ByteString msg = UA_BYTESTRING_NULL;
    UA_StatusCode retval = cm->allocNetworkBuffer(cm, channel->connectionId,
                                                  &msg, header.messageSize);
    if(retval != UA_STATUSCODE_GOOD)
        return;

    /* Encode and send the response */
    UA_Byte *bufPos = msg.data;
    const UA_Byte *bufEnd = &msg.data[msg.length];
    retval |= UA_encodeBinaryInternal(&header,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                      &bufPos, &bufEnd, NULL, NULL, NULL);
    retval |= UA_encodeBinaryInternal(error,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE],
                                      &bufPos, &bufEnd, NULL, NULL, NULL);
    (void)retval; /* Encoding of these cannot fail */
    msg.length = header.messageSize;
    cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &msg);
}

static void
UA_Chunk_delete(UA_Chunk *chunk) {
    if(chunk->copied)
        UA_ByteString_clear(&chunk->bytes);
    UA_free(chunk);
}

static void
deleteChunks(UA_SecureChannel *channel) {
    UA_Chunk *chunk, *chunk_tmp;
    TAILQ_FOREACH_SAFE(chunk, &channel->chunks, pointers, chunk_tmp) {
        TAILQ_REMOVE(&channel->chunks, chunk, pointers);
        UA_Chunk_delete(chunk);
    }
    channel->chunksCount = 0;
    channel->chunksLength = 0;
}

void
UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel) {
    deleteChunks(channel);
    if(channel->unprocessedCopied)
        UA_ByteString_clear(&channel->unprocessed);
}

void
UA_SecureChannel_shutdown(UA_SecureChannel *channel,
                          UA_ShutdownReason shutdownReason) {
    /* No open socket or already closing -> nothing to do */
    if(!UA_SecureChannel_isConnected(channel))
        return;

    /* Set the shutdown event for diagnostics */
    channel->shutdownReason= shutdownReason;

    /* Trigger the async closing of the connection */
    UA_ConnectionManager *cm = channel->connectionManager;
    cm->closeConnection(cm, channel->connectionId);
    channel->state = UA_SECURECHANNELSTATE_CLOSING;
}

void
UA_SecureChannel_clear(UA_SecureChannel *channel) {
    /* No sessions must be attached to this any longer */
    UA_assert(channel->sessions == NULL);

    /* Delete the channel context for the security policy */
    UA_SecurityPolicy *sp = channel->securityPolicy;
    if(sp) {
        sp->deleteChannelContext(sp, channel->channelContext);
        channel->securityPolicy = NULL;
        channel->channelContext = NULL;
        channel->enhancedSecurity = false;     /* No policy => not enhanced */
        channel->legacySequenceNumbers = true; /* No policy => legacy */
    }

    /* Remove remaining delayed callback */
    if(channel->connectionManager &&
       channel->connectionManager->eventSource.eventLoop) {
        UA_EventLoop *el = channel->connectionManager->eventSource.eventLoop;
        el->removeDelayedCallback(el, &channel->unprocessedDelayed);
    }

    /* The EventLoop connection is no longer valid */
    channel->connectionId = 0;
    channel->connectionManager = NULL;

    /* Clean up the SecurityToken */
    UA_ChannelSecurityToken_clear(&channel->securityToken);
    UA_ChannelSecurityToken_clear(&channel->altSecurityToken);

    /* Clean up certificate and nonces */
    UA_ByteString_clear(&channel->remoteCertificate);
    UA_ByteString_clear(&channel->localNonce);
    UA_ByteString_clear(&channel->remoteNonce);

    /* Clean up the v1.05.07 SecureChannel elements */
    UA_ByteString_clear(&channel->firstRequestSignature);
    UA_ByteString_clear(&channel->currentIKM);
    UA_ByteString_clear(&channel->channelThumbprint);

    /* Clean up endpointUrl and remoteAddress */
    UA_String_clear(&channel->endpointUrl);
    UA_String_clear(&channel->remoteAddress);

    /* Delete remaining chunks */
    UA_SecureChannel_deleteBuffered(channel);

    /* Clean up namespace mapping */
    UA_NamespaceMapping_delete(channel->namespaceMapping);
    channel->namespaceMapping = NULL;

    /* Reset the SecureChannel for reuse (in the client) */
    channel->securityMode = UA_MESSAGESECURITYMODE_INVALID;
    channel->shutdownReason = UA_SHUTDOWNREASON_CLOSE;
    memset(&channel->config, 0, sizeof(UA_ConnectionConfig));
    channel->receiveSequenceNumber = 0;
    channel->sendSequenceNumber = 0;

    /* Set the state to closed */
    channel->state = UA_SECURECHANNELSTATE_CLOSED;
    channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
}

UA_StatusCode
UA_SecureChannel_processHELACK(UA_SecureChannel *channel,
                               const UA_TcpAcknowledgeMessage *remoteConfig) {
    /* The lowest common version is used by both sides */
    if(channel->config.protocolVersion > remoteConfig->protocolVersion)
        channel->config.protocolVersion = remoteConfig->protocolVersion;

    /* Can we receive the max send size? */
    if(channel->config.sendBufferSize > remoteConfig->receiveBufferSize)
        channel->config.sendBufferSize = remoteConfig->receiveBufferSize;

    /* Can we send the max receive size? */
    if(channel->config.recvBufferSize > remoteConfig->sendBufferSize)
        channel->config.recvBufferSize = remoteConfig->sendBufferSize;

    channel->config.remoteMaxMessageSize = remoteConfig->maxMessageSize;
    channel->config.remoteMaxChunkCount = remoteConfig->maxChunkCount;

    /* Chunks of at least 8192 bytes must be permissible.
     * See Part 6, Clause 6.7.1 */
    if(channel->config.recvBufferSize < 8192 ||
       channel->config.sendBufferSize < 8192 ||
       (channel->config.remoteMaxMessageSize != 0 &&
        channel->config.remoteMaxMessageSize < 8192))
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

/* Send an OPN message using asymmetric encryption.
 * Specification part 6, 6.7.4: The OpenSecureChannel Messages are signed and
 * encrypted if the SecurityMode is not None (even if the SecurityMode is
 * SignOnly). */
UA_StatusCode
UA_SecureChannel_sendOPN(UA_SecureChannel *channel,
                         UA_UInt32 requestId, const void *content,
                         const UA_DataType *contentType) {
    if(!content || !contentType)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The SecurityPolicy must be configured before sending OPN */
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);

    /* Check for a valid security mode */
    UA_assert(channel->securityMode > UA_MESSAGESECURITYMODE_INVALID &&
              channel->securityMode <= UA_MESSAGESECURITYMODE_SIGNANDENCRYPT);

    /* The #None SecurityPolicy must use the NONE MessageSecurityMode.
     * All other SecurityPolicies must not. */
    UA_assert((sp->policyType == UA_SECURITYPOLICYTYPE_NONE) ==
              (channel->securityMode == UA_MESSAGESECURITYMODE_NONE));

    /* Can we use the connection manager? */
    UA_ConnectionManager *cm = channel->connectionManager;
    if(!UA_SecureChannel_isConnected(channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    /* Allocate the message buffer */
    UA_ByteString buf = UA_BYTESTRING_NULL;
    UA_StatusCode res = cm->allocNetworkBuffer(cm, channel->connectionId, &buf,
                                               channel->config.sendBufferSize);
    UA_CHECK_STATUS(res, return res);

    /* Restrict buffer to the available space for the payload */
    UA_Byte *buf_pos = buf.data;
    const UA_Byte *buf_end = &buf.data[buf.length];
    hideBytesAsym(channel, &buf_pos, &buf_end);

    /* Define variables here to pacify some compilers wrt goto */
    size_t securityHeaderLength, pre_sig_length, total_length, encryptedLength;

    /* Encode the message type and content */
    UA_EncodeBinaryOptions encOpts;
    memset(&encOpts, 0, sizeof(UA_EncodeBinaryOptions));
    encOpts.namespaceMapping = channel->namespaceMapping;
    res |= UA_NodeId_encodeBinary(&contentType->binaryEncodingId, &buf_pos, buf_end);
    res |= UA_encodeBinaryInternal(content, contentType, &buf_pos, &buf_end,
                                   &encOpts, NULL, NULL);
    UA_CHECK_STATUS(res, goto error);

    /* Compute the header length */
    securityHeaderLength = calculateAsymAlgSecurityHeaderLength(channel);

    /* Add padding to the chunk */
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE)
        padChunk(channel, &sp->asymSignatureAlgorithm, &sp->asymEncryptionAlgorithm,
                 &buf.data[UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength],
                 &buf_pos);

    /* The total message length */
    pre_sig_length = (uintptr_t)buf_pos - (uintptr_t)buf.data;
    total_length = pre_sig_length;
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE)
        total_length += sp->asymSignatureAlgorithm.
            getLocalSignatureSize(sp, channel->channelContext);

    /* The total message length is known here which is why we encode the headers
     * at this step and not earlier. */
    res = prependHeadersAsym(channel, buf.data, buf_end, total_length,
                             securityHeaderLength, requestId, &encryptedLength);
    UA_CHECK_STATUS(res, goto error);

    /* Add the signature and encrypt the message */
    res = signAndEncryptAsym(channel, pre_sig_length, &buf,
                             securityHeaderLength, total_length);
    UA_CHECK_STATUS(res, goto error);

    /* Send the message, the buffer is freed in the network layer */
    buf.length = encryptedLength;
    return cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &buf);

 error:
    cm->freeNetworkBuffer(cm, channel->connectionId, &buf);
    return res;
}

/* Will this chunk surpass the capacity of the SecureChannel for the message? */
static UA_StatusCode
adjustCheckMessageLimitsSym(UA_MessageContext *mc, size_t bodyLength) {
    mc->messageSizeSoFar += bodyLength;
    mc->chunksSoFar++;

    UA_SecureChannel *channel = mc->channel;
    if(mc->messageSizeSoFar > channel->config.localMaxMessageSize &&
       channel->config.localMaxMessageSize != 0)
        return UA_STATUSCODE_BADRESPONSETOOLARGE;

    if(mc->chunksSoFar > channel->config.localMaxChunkCount &&
       channel->config.localMaxChunkCount != 0)
        return UA_STATUSCODE_BADRESPONSETOOLARGE;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
encodeHeadersSym(UA_MessageContext *mc, size_t totalLength) {
    UA_SecureChannel *channel = mc->channel;
    UA_Byte *header_pos = mc->messageBuffer.data;

    UA_TcpMessageHeader header;
    header.messageTypeAndChunkType = mc->messageType;
    header.messageSize = (UA_UInt32)totalLength;
    if(mc->final)
        header.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
    else
        header.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE;

    UA_SequenceHeader seqHeader;
    seqHeader.requestId = mc->requestId;
    seqHeader.sequenceNumber = UA_SecureChannel_nextSequenceNumber(channel);

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_encodeBinaryInternal(&header, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                   &header_pos, &mc->buf_end, NULL, NULL, NULL);
    res |= UA_UInt32_encodeBinary(&channel->securityToken.channelId,
                                  &header_pos, mc->buf_end);
    res |= UA_UInt32_encodeBinary(&channel->securityToken.tokenId,
                                  &header_pos, mc->buf_end);
    res |= UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
                                   &header_pos, &mc->buf_end, NULL, NULL, NULL);
    return res;
}

static UA_StatusCode
sendSymmetricChunk(UA_MessageContext *mc) {
    UA_SecureChannel *channel = mc->channel;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_ConnectionManager *cm = channel->connectionManager;
    if(!UA_SecureChannel_isConnected(channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    /* The size of the message payload */
    size_t bodyLength = (uintptr_t)mc->buf_pos -
        (uintptr_t)&mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH];

    /* Early-declare variables so we can use a goto in the error case */
    size_t total_length = 0;
    size_t pre_sig_length = 0;

    /* Check if chunk exceeds the limits for the overall message */
    UA_StatusCode res = adjustCheckMessageLimitsSym(mc, bodyLength);
    UA_CHECK_STATUS(res, goto error);

    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                         "Send from a symmetric message buffer of length %lu "
                         "a message of header+payload length of %lu",
                         (long unsigned int)mc->messageBuffer.length,
                         (long unsigned int)
                         ((uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data));

    /* Add padding if the message is encrypted (not for AEAD policies) */
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
       !UA_SecurityPolicy_isAead(sp))
        padChunk(channel, &sp->symSignatureAlgorithm, &sp->symEncryptionAlgorithm,
                 &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH],
                 &mc->buf_pos);

    /* Compute the total message length */
    pre_sig_length = (uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data;
    total_length = pre_sig_length;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        total_length += sp->symSignatureAlgorithm.
            getLocalSignatureSize(sp, channel->channelContext);

    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                         "Send from a symmetric message buffer of length %lu "
                         "a message of length %lu",
                         (long unsigned int)mc->messageBuffer.length,
                         (long unsigned int)total_length);

    /* Space for the padding and the signature have been reserved in setBufPos() */
    UA_assert(total_length <= channel->config.sendBufferSize);

    /* Adjust the buffer size of the network layer */
    mc->messageBuffer.length = total_length;

    /* Generate and encode the header for symmetric messages */
    res = encodeHeadersSym(mc, total_length);
    UA_CHECK_STATUS(res, goto error);

    /* Sign and encrypt the messge */
    res = signAndEncryptSym(mc, pre_sig_length, total_length);
    UA_CHECK_STATUS(res, goto error);

    /* Send the chunk. The buffer is freed in the network layer. If sending goes
     * wrong, the connection is removed in the next iteration of the
     * SecureChannel. Set the SecureChannel to closing already. */
    res = cm->sendWithConnection(cm, channel->connectionId,
                                 &UA_KEYVALUEMAP_NULL, &mc->messageBuffer);
    if(res != UA_STATUSCODE_GOOD && UA_SecureChannel_isConnected(channel))
        channel->state = UA_SECURECHANNELSTATE_CLOSING;
    return res;

 error:
    /* Free the unused message buffer */
    cm->freeNetworkBuffer(cm, channel->connectionId, &mc->messageBuffer);
    return res;
}

/* Callback from the encoding layer. Send the chunk and replace the buffer. */
static UA_StatusCode
sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos,
                              const UA_Byte **buf_end) {
    /* Set buf values from encoding in the messagecontext */
    UA_MessageContext *mc = (UA_MessageContext *)data;
    mc->buf_pos = *buf_pos;
    mc->buf_end = *buf_end;

    /* Send out */
    UA_StatusCode res = sendSymmetricChunk(mc);
    UA_CHECK_STATUS(res, return res);

    /* Set a new buffer for the next chunk */
    UA_ConnectionManager *cm = mc->channel->connectionManager;
    if(!UA_SecureChannel_isConnected(mc->channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    res = cm->allocNetworkBuffer(cm, mc->channel->connectionId,
                                 &mc->messageBuffer,
                                 mc->channel->config.sendBufferSize);
    UA_CHECK_STATUS(res, return res);

    /* Hide bytes for header, padding and signature */
    setBufPos(mc);
    *buf_pos = mc->buf_pos;
    *buf_end = mc->buf_end;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
                        UA_UInt32 requestId, UA_MessageType messageType) {
    UA_CHECK(messageType == UA_MESSAGETYPE_MSG || messageType == UA_MESSAGETYPE_CLO,
             return UA_STATUSCODE_BADINTERNALERROR);

    UA_ConnectionManager *cm = channel->connectionManager;
    if(!UA_SecureChannel_isConnected(channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    /* Create the chunking info structure */
    mc->channel = channel;
    mc->requestId = requestId;
    mc->chunksSoFar = 0;
    mc->messageSizeSoFar = 0;
    mc->final = false;
    mc->messageBuffer = UA_BYTESTRING_NULL;
    mc->messageType = messageType;

    /* Allocate the message buffer */
    UA_StatusCode res =
        cm->allocNetworkBuffer(cm, channel->connectionId,
                               &mc->messageBuffer,
                               channel->config.sendBufferSize);
    UA_CHECK_STATUS(res, return res);

    /* Hide bytes for header, padding and signature */
    setBufPos(mc);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
                         const UA_DataType *contentType) {
    UA_EncodeBinaryOptions encOpts;
    memset(&encOpts, 0, sizeof(UA_EncodeBinaryOptions));
    encOpts.namespaceMapping = mc->channel->namespaceMapping;
    UA_StatusCode res =
        UA_encodeBinaryInternal(content, contentType, &mc->buf_pos, &mc->buf_end,
                                &encOpts, sendSymmetricEncodingCallback, mc);
    if(res != UA_STATUSCODE_GOOD && mc->messageBuffer.length > 0)
        UA_MessageContext_abort(mc);
    return res;
}

UA_StatusCode
UA_MessageContext_finish(UA_MessageContext *mc) {
    mc->final = true;
    return sendSymmetricChunk(mc);
}

void
UA_MessageContext_abort(UA_MessageContext *mc) {
    UA_ConnectionManager *cm = mc->channel->connectionManager;
    if(!UA_SecureChannel_isConnected(mc->channel))
        return;
    cm->freeNetworkBuffer(cm, mc->channel->connectionId, &mc->messageBuffer);
}

/* Send a MSG or CLO message using symmetric encryption */
static UA_StatusCode
sendSymmetric(UA_SecureChannel *channel, UA_UInt32 requestId,
              UA_MessageType messageType, void *payload,
              const UA_DataType *payloadType) {
    if(!channel || !payload || !payloadType)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(channel->state != UA_SECURECHANNELSTATE_OPEN)
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    UA_MessageContext mc;
    UA_StatusCode res = UA_MessageContext_begin(&mc, channel, requestId, messageType);
    UA_CHECK_STATUS(res, return res);

    /* Assert's required for clang-analyzer */
    UA_assert(mc.buf_pos ==
              &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]);
    UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]);

    res = UA_MessageContext_encode(&mc, &payloadType->binaryEncodingId,
                                   &UA_TYPES[UA_TYPES_NODEID]);
    UA_CHECK_STATUS(res, return res);

    res = UA_MessageContext_encode(&mc, payload, payloadType);
    UA_CHECK_STATUS(res, return res);

    return UA_MessageContext_finish(&mc);
}

UA_StatusCode
UA_SecureChannel_sendMSG(UA_SecureChannel *channel, UA_UInt32 requestId,
                         void *payload, const UA_DataType *payloadType) {
    return sendSymmetric(channel, requestId, UA_MESSAGETYPE_MSG,
                         payload, payloadType);
}

UA_StatusCode
UA_SecureChannel_sendCLO(UA_SecureChannel *channel, UA_UInt32 requestId,
                         UA_CloseSecureChannelRequest *req) {
    return sendSymmetric(channel, requestId, UA_MESSAGETYPE_CLO, req,
                         &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]);
}

/********************************/
/* Receive and Process Messages */
/********************************/

/* Does the sequence number match? Otherwise try to rollover. See Part 6,
 * Section 6.7.2.4 of the standard. */
#define UA_SEQUENCENUMBER_ROLLOVER 4294966271

UA_UInt32
UA_SecureChannel_nextSequenceNumber(UA_SecureChannel *channel) {
    /* channel->sendSequenceNumber mirrors the reference-stack counter: a
     * pre-increment value initialized to 0. The legacy scheme emits the
     * counter (first = 1); the non-legacy scheme emits counter-1 (first = 0). */
    UA_UInt64 next = (UA_UInt64)channel->sendSequenceNumber + 1;
    if(channel->legacySequenceNumbers) {
        /* Legacy rollover: the first number after the max is 1. */
        if(next > UA_SEQUENCENUMBER_ROLLOVER)
            next = 1;
        channel->sendSequenceNumber = (UA_UInt32)next;
        return channel->sendSequenceNumber;
    }
    /* Non-legacy: the counter wraps to 0 after UA_UINT32_MAX so the emitted
     * value (counter - 1) covers the full UInt32 range and then restarts at 0. */
    if(next > UA_UINT32_MAX)
        next = 0;
    channel->sendSequenceNumber = (UA_UInt32)next;
    return (channel->sendSequenceNumber == 0) ?
        UA_UINT32_MAX : (channel->sendSequenceNumber - 1);
}

#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
static UA_StatusCode
processSequenceNumberSym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) {
    if(sequenceNumber != channel->receiveSequenceNumber + 1) {
        /* The non-legacy (ECC) rollover from UA_UINT32_MAX to 0 is already
         * accepted by the check above (unsigned overflow makes
         * receiveSequenceNumber + 1 == 0). Only the legacy "< 1024" rollover
         * needs the special case below; non-legacy policies reject anything
         * that is not the immediate successor. */
        if(!channel->legacySequenceNumbers ||
           channel->receiveSequenceNumber + 1 <= UA_SEQUENCENUMBER_ROLLOVER ||
           sequenceNumber >= 1024)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        channel->receiveSequenceNumber = sequenceNumber - 1; /* Roll over */
    }
    ++channel->receiveSequenceNumber;
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
unpackPayloadOPN(UA_SecureChannel *channel, UA_Chunk *chunk) {
    UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
    size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */
    UA_UInt32 secureChannelId;
    UA_StatusCode res = UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId);
    UA_assert(res == UA_STATUSCODE_GOOD);

    UA_AsymmetricAlgorithmSecurityHeader asymHeader;
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &asymHeader,
             &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], NULL);
    UA_CHECK_STATUS(res, return res);

    /* Declare before the first goto to avoid crosses-initialization in C++ */
    UA_SecurityPolicy *sp = NULL;

    /* Client/Server-specific processing. Creates a SecurityPolicy context and
     * attaches it to the channel. For the client, the remote certificate has
     * been verified before connecting. For the server the remote certificate is
     * verified within processOPNHeader. */
    UA_assert(channel->processOPNHeader);
    res = channel->processOPNHeader(channel->processOPNHeaderApplication,
                                    channel, &asymHeader);
    UA_CHECK_STATUS(res, goto error);

    /* On the client side, take the SecureChannelId from the first response */
    if(secureChannelId != 0 && channel->securityToken.channelId == 0)
        channel->securityToken.channelId = secureChannelId;

    /* Check the ChannelId */
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
    if(secureChannelId != channel->securityToken.channelId) {
        /* Allow the channel id to be different if the sent channel id is zero
         * and the SecurityToken is not initialized. This only happens on the
         * server side before we had a chance to tell the client which ChannelId
         * to use. */
        if(secureChannelId != 0 || channel->securityToken.tokenId != 0) {
            res = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
            goto error;
        }
    }
#endif

    /* Generic header checking (for both client and server). Requires the
     * channel's SecurityPolicy. */
    res = checkAsymHeader(channel, &asymHeader);
    UA_CHECK_STATUS(res, goto error);

    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader);

    /* Decrypt the chunk payload */
    sp = channel->securityPolicy;
    res = decryptAndVerifyChunk(channel, &sp->asymSignatureAlgorithm,
                                &sp->asymEncryptionAlgorithm,
                                chunk->messageType, &chunk->bytes, offset);
    UA_CHECK_STATUS(res, return res);

    /* Decode the SequenceHeader */
    UA_SequenceHeader sequenceHeader;
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader,
                                  &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL);
    UA_CHECK_STATUS(res, return res);

    /* Set the sequence number for the channel from which to count up */
    channel->receiveSequenceNumber = sequenceHeader.sequenceNumber;
    chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */

    /* Use only the payload */
    chunk->bytes.data += offset;
    chunk->bytes.length -= offset;
    return UA_STATUSCODE_GOOD;

error:
    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader);
    return res;
}

static UA_StatusCode
unpackPayloadMSG(UA_SecureChannel *channel, UA_Chunk *chunk,
                 UA_DateTime nowMonotonic) {
    UA_CHECK_MEM(channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR);

    UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
    size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */
    UA_UInt32 secureChannelId;
    UA_UInt32 tokenId; /* SymmetricAlgorithmSecurityHeader */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId);
    res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &tokenId);
    UA_assert(offset == UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
    UA_assert(res == UA_STATUSCODE_GOOD);

#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
    /* Check the ChannelId. Non-opened channels have the id zero. */
    if(secureChannelId != channel->securityToken.channelId)
        return UA_STATUSCODE_BADSECURECHANNELIDINVALID;
#endif

    /* Check (and revolve) the SecurityToken */
    res = checkSymHeader(channel, tokenId, nowMonotonic);
    UA_CHECK_STATUS(res, return res);

    /* Decrypt the chunk payload */
    UA_SecurityPolicy *sp = channel->securityPolicy;
    res = decryptAndVerifyChunk(channel, &sp->symSignatureAlgorithm,
                                &sp->symEncryptionAlgorithm,
                                chunk->messageType, &chunk->bytes, offset);
    UA_CHECK_STATUS(res, return res);

    /* Check the sequence number. Skip sequence number checking for fuzzer to
     * improve coverage */
    UA_SequenceHeader sequenceHeader;
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader,
                                  &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL);
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    res |= processSequenceNumberSym(channel, sequenceHeader.sequenceNumber);
#endif
    UA_CHECK_STATUS(res, return res);

    chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */

    /* Use only the payload */
    chunk->bytes.data += offset;
    chunk->bytes.length -= offset;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
extractCompleteChunk(UA_SecureChannel *channel, UA_Chunk *chunk,
                     UA_DateTime nowMonotonic) {
    /* At least 8 byte needed for the header */
    size_t offset = channel->unprocessedOffset;
    size_t remaining = channel->unprocessed.length - offset;
    if(remaining < UA_SECURECHANNEL_MESSAGEHEADER_LENGTH)
        return UA_STATUSCODE_GOOD;

    /* Decoding the header cannot fail */
    UA_TcpMessageHeader hdr;
    UA_StatusCode res =
        UA_decodeBinaryInternal(&channel->unprocessed, &offset, &hdr,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], NULL);
    UA_assert(res == UA_STATUSCODE_GOOD);
    (void)res; /* pacify compilers if assert is ignored */
    UA_MessageType msgType = (UA_MessageType)
        (hdr.messageTypeAndChunkType & UA_BITMASK_MESSAGETYPE);
    UA_ChunkType chunkType = (UA_ChunkType)
        (hdr.messageTypeAndChunkType & UA_BITMASK_CHUNKTYPE);

    /* The message size is not allowed */
    if(hdr.messageSize < UA_SECURECHANNEL_MESSAGE_MIN_LENGTH)
        return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
    if(hdr.messageSize > channel->config.recvBufferSize)
        return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;

    /* Incomplete chunk. Continue processing later. */
    if(hdr.messageSize > remaining)
        return UA_STATUSCODE_GOOD;

    /* Set the chunk information */
    chunk->bytes.data = channel->unprocessed.data + channel->unprocessedOffset;
    chunk->bytes.length = hdr.messageSize;
    chunk->messageType = msgType;
    chunk->chunkType = chunkType;
    chunk->requestId = 0;
    chunk->copied = false;

    /* Increase the unprocessed offset */
    channel->unprocessedOffset += hdr.messageSize;

    /* Validate, decrypt and unpack the chunk payload */
    switch(msgType) {
    case UA_MESSAGETYPE_OPN:
        if(chunkType != UA_CHUNKTYPE_FINAL)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        if(channel->state != UA_SECURECHANNELSTATE_OPEN &&
           channel->state != UA_SECURECHANNELSTATE_OPN_SENT &&
           channel->state != UA_SECURECHANNELSTATE_ACK_SENT)
            return UA_STATUSCODE_BADINVALIDSTATE;
        res = unpackPayloadOPN(channel, chunk);
        break;

    case UA_MESSAGETYPE_MSG:
    case UA_MESSAGETYPE_CLO:
        if(chunkType != UA_CHUNKTYPE_FINAL &&
           chunkType != UA_CHUNKTYPE_INTERMEDIATE &&
           chunkType != UA_CHUNKTYPE_ABORT)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        if(channel->state != UA_SECURECHANNELSTATE_OPEN)
            return UA_STATUSCODE_BADINVALIDSTATE;
        res = unpackPayloadMSG(channel, chunk, nowMonotonic);
        break;

    case UA_MESSAGETYPE_RHE:
    case UA_MESSAGETYPE_HEL:
    case UA_MESSAGETYPE_ACK:
    case UA_MESSAGETYPE_ERR:
        if(chunkType != UA_CHUNKTYPE_FINAL)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        /* Hide the message header */
        chunk->bytes.data += UA_SECURECHANNEL_MESSAGEHEADER_LENGTH;
        chunk->bytes.length -= UA_SECURECHANNEL_MESSAGEHEADER_LENGTH;
        break;

    default:
        res = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        break;
    }
    return res;
}

UA_StatusCode
UA_SecureChannel_loadBuffer(UA_SecureChannel *channel, const UA_ByteString buffer) {
    /* Append to the previous unprocessed buffer */
    if(channel->unprocessed.length > 0) {
        UA_assert(channel->unprocessedCopied == true);

        UA_Byte *t = (UA_Byte*)
            UA_realloc(channel->unprocessed.data,
                       channel->unprocessed.length + buffer.length);
        if(!t)
            return UA_STATUSCODE_BADOUTOFMEMORY;

        if(buffer.length)
            memcpy(t + channel->unprocessed.length, buffer.data, buffer.length);
        channel->unprocessed.data = t;
        channel->unprocessed.length += buffer.length;
        return UA_STATUSCODE_GOOD;
    }

    /* Use the new buffer directly */
    channel->unprocessed = buffer;
    channel->unprocessedCopied = false;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_SecureChannel_getCompleteMessage(UA_SecureChannel *channel,
                                    UA_MessageType *messageType, UA_UInt32 *requestId,
                                    UA_ByteString *payload, UA_Boolean *copied,
                                    UA_DateTime nowMonotonic) {
    UA_Chunk chunk, *pchunk;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

 extract_chunk:
    /* Extract+decode the next chunk from the buffer */
    memset(&chunk, 0, sizeof(UA_Chunk));
    res = extractCompleteChunk(channel, &chunk, nowMonotonic);
    if(chunk.bytes.length == 0 || res != UA_STATUSCODE_GOOD)
        return res; /* Error or no complete chunk could be extracted */

    /* Process the chunk */
    switch(chunk.chunkType) {
    case UA_CHUNKTYPE_ABORT:
        /* Remove all chunks received so far. Then continue extracting chunks. */
        deleteChunks(channel);
        if(chunk.copied)
            UA_ByteString_clear(&chunk.bytes);
        goto extract_chunk;

    case UA_CHUNKTYPE_INTERMEDIATE:
        /* Validate the resource limits */
        if((channel->config.localMaxChunkCount != 0 &&
            channel->chunksCount >= channel->config.localMaxChunkCount) ||
           (channel->config.localMaxMessageSize != 0 &&
            channel->chunksLength + chunk.bytes.length > channel->config.localMaxMessageSize)) {
            if(chunk.copied)
                UA_ByteString_clear(&chunk.bytes);
            return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;
        }

        /* Add the chunk to the queue. Then continue extracting more chunks. */
        pchunk = (UA_Chunk*)UA_malloc(sizeof(UA_Chunk));
        if(!pchunk) {
            if(chunk.copied)
                UA_ByteString_clear(&chunk.bytes);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        *pchunk = chunk;
        TAILQ_INSERT_TAIL(&channel->chunks, pchunk, pointers);
        channel->chunksCount++;
        channel->chunksLength += pchunk->bytes.length;
        goto extract_chunk;

    case UA_CHUNKTYPE_FINAL:
    default:
        UA_assert(chunk.chunkType == UA_CHUNKTYPE_FINAL); /* Was checked before */
        break; /* A final chunk was received -- assemble the message */
    }

    /* Compute the message size */
    size_t messageSize = chunk.bytes.length;
    UA_Chunk *first = NULL;
    TAILQ_FOREACH(pchunk, &channel->chunks, pointers) {
        if(chunk.requestId != pchunk->requestId)
            continue;
        if(chunk.messageType != pchunk->messageType) {
            if(chunk.copied)
                UA_ByteString_clear(&chunk.bytes);
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        }
        if(!first)
            first = pchunk;
        messageSize += pchunk->bytes.length;
    }

    /* Validate the assembled message size */
    if(channel->config.localMaxMessageSize != 0 &&
       messageSize > channel->config.localMaxMessageSize) {
        if(chunk.copied)
            UA_ByteString_clear(&chunk.bytes);
        return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;
    }

    /* Assemble the full payload and store it in chunk.bytes */
    if(messageSize > chunk.bytes.length) {
        UA_assert(first != NULL);

        /* Allocate the full memory and initialize with the first chunk content.
         * Use realloc to speed up. */
        UA_ByteString message;
        if(first->copied) {
            message.data = (UA_Byte*)UA_realloc(first->bytes.data, messageSize);
        } else {
            message.data = (UA_Byte*)UA_malloc(messageSize);
            if(message.data)
                memcpy(message.data, first->bytes.data, first->bytes.length);
        }
        if(!message.data) {
            if(chunk.copied)
                UA_ByteString_clear(&chunk.bytes);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        message.length = first->bytes.length;

        /* Remove the the first chunk */
        pchunk = TAILQ_NEXT(first, pointers);
        first->copied = false;
        channel->chunksCount--;
        channel->chunksLength -= first->bytes.length;
        TAILQ_REMOVE(&channel->chunks, first, pointers);
        UA_Chunk_delete(first);

        /* Copy over the content from the remaining intermediate chunks.
         * And remove them right away. */
        UA_Chunk *next;
        for(; pchunk; pchunk = next) {
            next = TAILQ_NEXT(pchunk, pointers);
            if(chunk.requestId != pchunk->requestId)
                continue;
            memcpy(message.data + message.length, pchunk->bytes.data, pchunk->bytes.length);
            message.length += pchunk->bytes.length;
            channel->chunksCount--;
            channel->chunksLength -= pchunk->bytes.length;
            TAILQ_REMOVE(&channel->chunks, pchunk, pointers);
            UA_Chunk_delete(pchunk);
        }

        /* Copy over the content from the final chunk */
        memcpy(message.data + message.length, chunk.bytes.data, chunk.bytes.length);
        message.length += chunk.bytes.length;
        UA_assert(message.length == messageSize);

        /* Set assembled message as the content of the final chunk */
        if(chunk.copied)
            UA_ByteString_clear(&chunk.bytes);
        chunk.bytes = message;
        chunk.copied = true;
    }

    /* Return the assembled message */
    *requestId = chunk.requestId;
    *messageType = chunk.messageType;
    *payload = chunk.bytes;
    *copied = chunk.copied;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_SecureChannel_persistBuffer(UA_SecureChannel *channel) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Persist the chunks */
    UA_Chunk *chunk;
    TAILQ_FOREACH(chunk, &channel->chunks, pointers) {
        if(chunk->copied)
            continue;
        UA_ByteString tmp = UA_BYTESTRING_NULL;
        res |= UA_ByteString_copy(&chunk->bytes, &tmp);
        chunk->bytes = tmp;
        chunk->copied = true;
    }

    /* No unprocessed bytes remaining */
    UA_assert(channel->unprocessed.length >= channel->unprocessedOffset);
    if(channel->unprocessed.length == channel->unprocessedOffset) {
        if(channel->unprocessedCopied)
            UA_ByteString_clear(&channel->unprocessed);
        else
            UA_ByteString_init(&channel->unprocessed);
        channel->unprocessedOffset = 0;
        return res;
    }

    /* Allocate a new unprocessed ByteString.
     * tmp is the empty string if malloc fails. */
    UA_ByteString tmp = UA_BYTESTRING_NULL;
    UA_ByteString remaining = channel->unprocessed;
    remaining.data += channel->unprocessedOffset;
    remaining.length -= channel->unprocessedOffset;
    res |= UA_ByteString_copy(&remaining, &tmp);
    if(channel->unprocessedCopied)
        UA_ByteString_clear(&channel->unprocessed);
    channel->unprocessed = tmp;
    channel->unprocessedOffset = 0;
    channel->unprocessedCopied = true;
    return res;
}

/**** amalgamated original file "/src/ua_securechannel_crypto.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2016-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


UA_StatusCode
UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
    UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new local nonce");

    /* Is the length of the previous nonce correct? */
    size_t nonceLength = sp->nonceLength;
    if(nonceLength == 0)
        return UA_STATUSCODE_GOOD;

    /* At least 32 byte */
    if(nonceLength < 32)
        nonceLength = 32;

    if(channel->localNonce.length != nonceLength) {
        UA_ByteString_clear(&channel->localNonce);
        UA_StatusCode res = UA_ByteString_allocBuffer(&channel->localNonce, nonceLength);
        UA_CHECK_STATUS(res, return res);
    }

    /* Generate the nonce */
    channel->localNonce.data[0] = 'e';
    channel->localNonce.data[1] = 'p';
    channel->localNonce.data[2] = 'h';
    return sp->generateNonce(sp, channel->channelContext, &channel->localNonce);
}

/* OPC UA Part 6 v1.05.07 §6.8.1 step 2 "Extract" — IKM chaining (enhanced
 * policies only). The IKM is XORed with the new shared secret on each renewal;
 * the accumulator is the curve's coordinate size (half the nonceLength, e.g. 32
 * bytes for P-256). It is carried through sp->generateKey without changing that
 * signature by prepending it to the `secret` ByteString: the backend's
 * DeriveKeys helper detects the prepend (key1 longer than the ephemeral public
 * key), XORs, and writes the chained IKM back into the slot. */
#define IKM_PREPEND_LENGTH(channel) \
    ((channel)->enhancedSecurity ? ((channel)->securityPolicy->nonceLength / 2) : 0)

/* Allocate and fill the prepend buffer [currentIKM | nonce] when
 * chaining is active; otherwise point *outInput at the original
 * nonce. The caller frees *outCombined with UA_ByteString_clear. */
static UA_StatusCode
prepareKeyInput(UA_SecureChannel *channel, const UA_ByteString *nonce,
                UA_ByteString *outInput, UA_ByteString *outCombined) {
    size_t ikmLen = IKM_PREPEND_LENGTH(channel);
    if(ikmLen == 0) {
        *outInput = *nonce;
        *outCombined = UA_BYTESTRING_NULL;
        return UA_STATUSCODE_GOOD;
    }
    UA_StatusCode res =
        UA_ByteString_allocBuffer(outCombined, ikmLen + nonce->length);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    if(channel->currentIKM.length == ikmLen)
        memcpy(outCombined->data, channel->currentIKM.data, ikmLen);
    else
        memset(outCombined->data, 0, ikmLen);
    memcpy(outCombined->data + ikmLen, nonce->data, nonce->length);
    *outInput = *outCombined;
    return UA_STATUSCODE_GOOD;
}

/* Pull the (possibly updated) IKM from the prepend slot and store
 * it as channel->currentIKM. Called only by the local-keys pass;
 * the remote-keys pass leaves the accumulator untouched. */
static UA_StatusCode
captureIKMSlot(UA_SecureChannel *channel, const UA_ByteString *combined) {
    size_t ikmLen = IKM_PREPEND_LENGTH(channel);
    if(ikmLen == 0)
        return UA_STATUSCODE_GOOD;
    UA_ByteString_clear(&channel->currentIKM);
    UA_ByteString ikmSlot = {ikmLen, combined->data};
    return UA_ByteString_copy(&ikmSlot, &channel->currentIKM);
}

UA_StatusCode
UA_SecureChannel_generateLocalKeys(UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
    UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new local keys");

    void *cc = channel->channelContext;
    const UA_SecurityPolicyEncryptionAlgorithm *ea = &sp->symEncryptionAlgorithm;

    /* Generate symmetric key buffer of the required length. The block size is
     * identical for local/remote. For AEAD ciphers the IV length differs from
     * the block size, so use getLocalIvLength when available. */
    UA_ByteString buf;
    size_t encrKL = ea->getLocalKeyLength(sp, cc);
    size_t encrBS = ea->getRemoteBlockSize(sp, cc);
    size_t ivLen = ea->getLocalIvLength ? ea->getLocalIvLength(sp, cc) : encrBS;
    size_t signKL = sp->symSignatureAlgorithm.getLocalKeyLength(sp, cc);
    if(ivLen + signKL + encrKL == 0)
        return UA_STATUSCODE_GOOD; /* No keys to generate */

    UA_StatusCode res = UA_ByteString_allocBuffer(&buf, ivLen + signKL + encrKL);
    UA_CHECK_STATUS(res, return res);
    UA_ByteString localSigningKey = {signKL, buf.data};
    UA_ByteString localEncryptingKey = {encrKL, &buf.data[signKL]};
    UA_ByteString localIv = {ivLen, &buf.data[signKL + encrKL]};

    /* TODO: Signal that no ECC salt is generated. Find a clean solution for this.  */
    buf.data[0] = 0x00;

    /* Build the IKM-prefixed `secret` input (the helper detects
     * the prepend via the length mismatch against the local
     * ephemeral public key). The `seed` arg is passed unchanged —
     * the helper uses it as the alternate ephemeral public key
     * candidate and as part of the salt, so the prepend must not
     * appear there. */
    UA_ByteString secretInput, seedInput = channel->localNonce;
    UA_ByteString secretCombined = UA_BYTESTRING_NULL;
    res = prepareKeyInput(channel, &channel->remoteNonce,
                         &secretInput, &secretCombined);
    UA_CHECK_STATUS(res, goto error);

    /* Generate key. The policy's wrapper detects the prepend (via the
     * length mismatch in key1 vs the local ephemeral public key) and
     * performs the IKM chaining, deriving against the *previous*
     * accumulator (channel->currentIKM). The new accumulator is NOT
     * promoted here: the local- and remote-keys passes of one OPN must
     * both derive against the same previous accumulator, so the
     * advance to IKM_n happens exactly once, in generateRemoteKeys
     * (the last of the two passes). */
    res = sp->generateKey(sp, cc, &secretInput, &seedInput, &buf);
    UA_CHECK_STATUS(res, goto error);

    /* Set the channel context */
    res |= sp->setLocalSymSigningKey(sp, cc, &localSigningKey);
    res |= sp->setLocalSymEncryptingKey(sp, cc, &localEncryptingKey);
    res |= sp->setLocalSymIv(sp, cc, &localIv);

 error:
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(sp->logger, channel,
                             "Could not generate local keys (%s)",
                             UA_StatusCode_name(res));
    }
    UA_ByteString_clear(&buf);
    UA_ByteString_clear(&secretCombined);
    return res;
}

UA_StatusCode
generateRemoteKeys(UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
    UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new remote keys");

    void *cc = channel->channelContext;
    const UA_SecurityPolicyEncryptionAlgorithm *ea = &sp->symEncryptionAlgorithm;

    /* Generate symmetric key buffer of the required length. For AEAD ciphers
     * the IV length differs from the block size, so use getLocalIvLength when
     * available. */
    UA_ByteString buf;
    size_t encrKL = ea->getRemoteKeyLength(sp, cc);
    size_t encrBS = ea->getRemoteBlockSize(sp, cc);
    size_t ivLen = ea->getLocalIvLength ? ea->getLocalIvLength(sp, cc) : encrBS;
    size_t signKL = sp->symSignatureAlgorithm.getRemoteKeyLength(sp, cc);
    if(ivLen + signKL + encrKL == 0)
        return UA_STATUSCODE_GOOD; /* No keys to generate */

    UA_StatusCode res = UA_ByteString_allocBuffer(&buf, ivLen + signKL + encrKL);
    UA_CHECK_STATUS(res, return res);
    UA_ByteString remoteSigningKey = {signKL, buf.data};
    UA_ByteString remoteEncryptingKey = {encrKL, &buf.data[signKL]};
    UA_ByteString remoteIv = {ivLen, &buf.data[signKL + encrKL]};

    /* TODO: Signal that no ECC salt is generated. Find a clean solution for this.  */
    buf.data[0] = 0x00;

    /* Build the IKM-prefixed `secret` input. Both the local- and
     * remote-keys passes of one OPN derive against the *same* previous
     * accumulator (channel->currentIKM); generateLocalKeys deliberately
     * did not advance it. The `seed` arg is passed unchanged — the
     * helper uses it as the alternate ephemeral public key candidate
     * and as part of the salt, so the prepend must not appear there. */
    UA_ByteString secretInput, seedInput = channel->remoteNonce;
    UA_ByteString secretCombined = UA_BYTESTRING_NULL;
    res = prepareKeyInput(channel, &channel->localNonce,
                         &secretInput, &secretCombined);
    UA_CHECK_STATUS(res, goto error);

    /* Generate key. The policy's wrapper XORs the previous accumulator
     * with the new shared secret and writes the result (IKM_n) back
     * into secretCombined. */
    res = sp->generateKey(sp, cc, &secretInput, &seedInput, &buf);
    UA_CHECK_STATUS(res, goto error);

    /* This is the last derivation of the OPN: promote the just-updated
     * IKM slot into channel->currentIKM so the next renewal chains from
     * IKM_n. (On the first OPN currentIKM was empty, so IKM_0 == the raw
     * shared secret for both passes — matching the spec's "no chaining
     * on the first OpenSecureChannel".) */
    res = captureIKMSlot(channel, &secretCombined);
    if(res != UA_STATUSCODE_GOOD) {
        res = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Set the channel context */
    res |= sp->setRemoteSymSigningKey(sp, cc, &remoteSigningKey);
    res |= sp->setRemoteSymEncryptingKey(sp, cc, &remoteEncryptingKey);
    res |= sp->setRemoteSymIv(sp, cc, &remoteIv);

 error:
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(sp->logger, channel,
                               "Could not generate remote keys (%s)",
                               UA_StatusCode_name(res));
    }
    UA_ByteString_clear(&buf);
    UA_ByteString_clear(&secretCombined);
    return res;
}

/* v1.05.07 channel-bound SignatureData (SecureChannelEnhancements): the
 * CreateSession / ActivateSession signatures are bound to the SecureChannel by
 * prepending the ChannelThumbprint and including certificate hashes (not the
 * raw certs). */

/* The certificate hash is provided by the crypto backend via the global
 * UA_SecurityPolicy_hashCertificate (the algorithm is derived from the policy
 * URI). Wrapped here so this file links without a crypto backend - the
 * builders below are only reached at runtime for enhanced-security policies,
 * which only exist when encryption is enabled. */
#ifdef UA_ENABLE_ENCRYPTION
static UA_StatusCode
hashCert(const UA_SecurityPolicy *sp, const UA_ByteString *cert,
         UA_ByteString *hash) {
    return UA_SecurityPolicy_hashCertificate(sp, cert, hash);
}
#else
static UA_StatusCode
hashCert(const UA_SecurityPolicy *sp, const UA_ByteString *cert,
         UA_ByteString *hash) {
    (void)sp; (void)cert; (void)hash;
    return UA_STATUSCODE_BADINTERNALERROR;
}
#endif

/* Assemble a channel-bound SignatureData (OPC UA Part 6 v1.05.07,
 * SecureChannelEnhancements). All three share the shape
 *   channelThumbprint | nonceA | H(cert_0) .. H(cert_n-1) | nonceB
 * and differ only in which certificate hashes appear and the nonce order:
 *
 *   CreateSession ServerSignature   (server signs, client verifies):
 *     TP | clientNonce | H(serverChannelCert) | H(clientChannelCert) | serverNonce
 *   ActivateSession ClientSignature (client signs, server verifies):
 *     TP | serverNonce | H(serverAppCert) | H(serverChannelCert) |
 *                        H(clientChannelCert) | clientNonce
 *   ActivateSession user-token sig  (client signs w/ user key, server verifies):
 *     TP | serverNonce | H(serverAppCert) | H(serverChannelCert) |
 *                        H(clientAppCert) | H(clientChannelCert) | clientNonce
 *
 * H() = the policy's curve hash of the leaf DER. Both peers must produce the
 * SAME bytes, so each side maps the logical certificate roles onto its own
 * local vs. remote view (the certs are channel-scoped: app == channel cert in
 * open62541, hence the duplicated hashes). The user/X.509-token certificate is
 * NOT part of the signed data (it is conveyed and validated separately).
 *
 *   logical cert role      server passes               client passes
 *   --------------------------------------------------------------------------
 *   server App / Channel   sp->localCertificate        channel->remoteCertificate
 *   client App / Channel   channel->remoteCertificate  sp->localCertificate
 *
 *   serverNonce = the session ServerNonce, clientNonce = the session
 *   ClientNonce (the same value on both sides). */
#define UA_MAX_SIGDATA_CERTS 4
static UA_StatusCode
buildChannelBoundSignatureData(const UA_SecureChannel *channel,
                               const UA_ByteString *firstNonce,
                               const UA_ByteString *const *certs, size_t certCount,
                               const UA_ByteString *lastNonce, UA_ByteString *out) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    if(!sp || !channel->enhancedSecurity || certCount > UA_MAX_SIGDATA_CERTS ||
       channel->channelThumbprint.length == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Hash the certificates. The inputs may be DER chains (e.g. the OPN
     * SenderCertificate stored in remoteCertificate), so hash only the leaf -
     * independent of how a given crypto backend's hashCert handles a chain. */
    UA_ByteString hashes[UA_MAX_SIGDATA_CERTS];
    for(size_t i = 0; i < UA_MAX_SIGDATA_CERTS; i++)
        hashes[i] = UA_BYTESTRING_NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    size_t hashesLen = 0;
    for(size_t i = 0; i < certCount && res == UA_STATUSCODE_GOOD; i++) {
        UA_ByteString leaf = getLeafCertificate(*certs[i]);
        res = hashCert(sp, &leaf, &hashes[i]);
        hashesLen += hashes[i].length;
    }
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* channelThumbprint | firstNonce | hashes | lastNonce */
    const UA_ByteString *tp = &channel->channelThumbprint;
    res = UA_ByteString_allocBuffer(out, tp->length + firstNonce->length +
                                    hashesLen + lastNonce->length);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    size_t o = 0;
    memcpy(out->data + o, tp->data, tp->length); o += tp->length;
    memcpy(out->data + o, firstNonce->data, firstNonce->length); o += firstNonce->length;
    for(size_t i = 0; i < certCount; i++) {
        memcpy(out->data + o, hashes[i].data, hashes[i].length);
        o += hashes[i].length;
    }
    memcpy(out->data + o, lastNonce->data, lastNonce->length);

 cleanup:
    for(size_t i = 0; i < certCount; i++)
        UA_ByteString_clear(&hashes[i]);
    return res;
}

/* CreateSession ServerSignature (see the layout table above). */
UA_StatusCode
UA_SecureChannel_buildCreateSessionSignatureData(
    const UA_SecureChannel *channel, const UA_ByteString *clientNonce,
    const UA_ByteString *serverNonce, const UA_ByteString *serverChannelCert,
    const UA_ByteString *clientChannelCert, UA_ByteString *out) {
    const UA_ByteString *certs[] = {serverChannelCert, clientChannelCert};
    return buildChannelBoundSignatureData(channel, clientNonce, certs, 2,
                                          serverNonce, out);
}

/* ActivateSession ClientSignature (see the layout table above). */
UA_StatusCode
UA_SecureChannel_buildActivateSessionSignatureData(
    const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
    const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
    const UA_ByteString *serverChannelCert, const UA_ByteString *clientChannelCert,
    UA_ByteString *out) {
    const UA_ByteString *certs[] = {serverAppCert, serverChannelCert, clientChannelCert};
    return buildChannelBoundSignatureData(channel, serverNonce, certs, 3,
                                          clientNonce, out);
}

/* ActivateSession X.509 user-token signature (see the layout table above). */
UA_StatusCode
UA_SecureChannel_buildUserTokenSignatureData(
    const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
    const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
    const UA_ByteString *serverChannelCert, const UA_ByteString *clientAppCert,
    const UA_ByteString *clientChannelCert, UA_ByteString *out) {
    const UA_ByteString *certs[] = {serverAppCert, serverChannelCert,
                                    clientAppCert, clientChannelCert};
    return buildChannelBoundSignatureData(channel, serverNonce, certs, 4,
                                          clientNonce, out);
}

/***************************/
/* Send Asymmetric Message */
/***************************/

/* The length of the static header content */
#define UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH 12

size_t
calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);

    size_t asymHeaderLength = UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH +
                              sp->policyUri.length;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
        return asymHeaderLength;

    /* OPN is always encrypted even if the mode is sign only */
    asymHeaderLength += 20; /* Thumbprints are always 20 byte long */
    asymHeaderLength += sp->localCertificate.length;
    return asymHeaderLength;
}

UA_StatusCode
prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos,
                   const UA_Byte *buf_end, size_t totalLength,
                   size_t securityHeaderLength, UA_UInt32 requestId,
                   size_t *const encryptedLength) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);

    void *cc = channel->channelContext;

    *encryptedLength = totalLength;
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE) {
        size_t dataToEncryptLength = totalLength -
            (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength);
        size_t plainTextBlockSize = sp->asymEncryptionAlgorithm.
            getRemotePlainTextBlockSize(sp, cc);
        size_t encryptedBlockSize = sp->asymEncryptionAlgorithm.
            getRemoteBlockSize(sp, cc);

        /* Padding always fills up the last block */
        UA_assert(plainTextBlockSize > 0);
        UA_assert(dataToEncryptLength % plainTextBlockSize == 0);
        size_t blocks = dataToEncryptLength / plainTextBlockSize;
        *encryptedLength = totalLength + blocks * (encryptedBlockSize - plainTextBlockSize);
    }

    UA_TcpMessageHeader messageHeader;
    messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL;
    messageHeader.messageSize = (UA_UInt32)*encryptedLength;
    UA_UInt32 secureChannelId = channel->securityToken.channelId;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_encodeBinaryInternal(&messageHeader,
                                   &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                   &header_pos, &buf_end, NULL, NULL, NULL);
    res |= UA_UInt32_encodeBinary(&secureChannelId, &header_pos, buf_end);
    UA_CHECK_STATUS(res, return res);

    UA_AsymmetricAlgorithmSecurityHeader asymHeader;
    UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader);
    asymHeader.securityPolicyUri = sp->policyUri;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        asymHeader.senderCertificate = sp->localCertificate;
        asymHeader.receiverCertificateThumbprint.length = 20;
        asymHeader.receiverCertificateThumbprint.data = channel->remoteCertificateThumbprint;
    }
    res = UA_encodeBinaryInternal(&asymHeader,
                                  &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER],
                                  &header_pos, &buf_end, NULL, NULL, NULL);
    UA_CHECK_STATUS(res, return res);

    UA_SequenceHeader seqHeader;
    seqHeader.requestId = requestId;
    seqHeader.sequenceNumber = UA_SecureChannel_nextSequenceNumber(channel);
    res = UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
                                  &header_pos, &buf_end, NULL, NULL, NULL);
    return res;
}

void
hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start,
              const UA_Byte **buf_end) {
    /* Set buf_start to the beginning of the encrypted body */
    *buf_start += UA_SECURECHANNEL_CHANNELHEADER_LENGTH;
    *buf_start += calculateAsymAlgSecurityHeaderLength(channel);

    /* Hide only the SequenceHeader for None  */
    if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) {
        *buf_start += UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH;
        return;
    }

    /* The max plaintext length depends on the number of encrypted blocks that
     * can fit into the remaining chunk */
    void *cc = channel->channelContext;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    size_t plainTextBlockSize =
        sp->asymEncryptionAlgorithm.getRemotePlainTextBlockSize(sp, cc);
    size_t encryptedBlockSize =
        sp->asymEncryptionAlgorithm.getRemoteBlockSize(sp, cc);

    size_t max_encrypted = (size_t)(*buf_end - *buf_start);
    UA_assert(encryptedBlockSize > 0);
    size_t max_blocks = max_encrypted / encryptedBlockSize;
    size_t max_plaintext = max_blocks * plainTextBlockSize;

    /* Reserve plaintext length for the SequenceHeader and Footer.
     * But don't reserve for the the padding itself -- which can be zero. */
    max_plaintext -= UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH;
    max_plaintext -= sp->asymSignatureAlgorithm.getLocalSignatureSize(sp, cc);
    UA_Boolean extraPadding =
        (sp->asymEncryptionAlgorithm.getRemoteKeyLength(sp, cc) > 2048);
    max_plaintext -= (UA_LIKELY(!extraPadding)) ? 1u : 2u;

    /* Adjust the buffer */
    *buf_end = *buf_start + max_plaintext;
    *buf_start += UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH;
}

/* Assumes that pos can be advanced to the end of the current block */
void
padChunk(UA_SecureChannel *channel,
         const UA_SecurityPolicySignatureAlgorithm *sa,
         const UA_SecurityPolicyEncryptionAlgorithm *ea,
         const UA_Byte *start, UA_Byte **pos) {
    UA_SecurityPolicy *sp = channel->securityPolicy;
    void *cc = channel->channelContext;

    const size_t bytesToWrite = (uintptr_t)*pos - (uintptr_t)start;

    size_t signatureSize = sa->getLocalSignatureSize(sp, cc);
    size_t plainTextBlockSize = ea->getRemotePlainTextBlockSize(sp, cc);
    UA_Boolean extraPadding = (ea->getRemoteKeyLength(sp, cc) > 2048);
    size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u;

    UA_assert(plainTextBlockSize > 0);
    size_t lastBlock = ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize);
    size_t paddingLength = (lastBlock != 0) ? plainTextBlockSize - lastBlock : 0;

    UA_assert((bytesToWrite + signatureSize +
               paddingBytes + paddingLength) % plainTextBlockSize == 0);

    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                         "Add %lu bytes of padding plus %lu padding size bytes",
                         (long unsigned int)paddingLength,
                         (long unsigned int)paddingBytes);

    /* Write the padding. This is <= because the paddingSize byte also has to be
     * written */
    UA_Byte paddingByte = (UA_Byte)paddingLength;
    for(size_t i = 0; i <= paddingLength; ++i) {
        **pos = paddingByte;
        ++*pos;
    }

    /* Write the extra padding byte if required */
    if(extraPadding) {
        **pos = (UA_Byte)(paddingLength >> 8u);
        ++*pos;
    }
}

UA_StatusCode
signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength,
                   UA_ByteString *buf, size_t securityHeaderLength,
                   size_t totalLength) {
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    const UA_SecurityPolicy *sp = channel->securityPolicy;
    void *cc = channel->channelContext;

    /* OPC UA Part 6 v1.05.07 §6.7.5 "ChannelThumbprint" (enhanced policies,
     * FIRST OPN only — an empty channelThumbprint identifies the first OPN; NOT
     * on renewals. The OPN response signature is extended with the first OPN
     * request signature: the client (request side) stores its just-computed
     * signature for the later response verify; the server (response side)
     * appends the request signature captured by decryptAndVerifyChunk to the
     * data being signed. */
    UA_Boolean firstOPN = (channel->enhancedSecurity &&
                           channel->channelThumbprint.length == 0);
    UA_ByteString *appendSig = NULL;
    if(firstOPN && channel->firstRequestSignature.length > 0)
        appendSig = &channel->firstRequestSignature; /* server: extend signed data */

    size_t sigsize = sp->asymSignatureAlgorithm.getLocalSignatureSize(sp, cc);

    /* Prepare the data to sign. If we need to append the request
     * signature, build a contiguous buffer [body | requestSig] and sign
     * that. Otherwise sign the body in-place. */
    UA_ByteString signature = {sigsize, buf->data + preSignLength};
    UA_StatusCode retval;

    if(appendSig) {
        size_t bodyLen = preSignLength;
        size_t extLen = bodyLen + appendSig->length;
        UA_Byte *ext = (UA_Byte*)UA_malloc(extLen);
        if(!ext)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        memcpy(ext, buf->data, bodyLen);
        memcpy(ext + bodyLen, appendSig->data, appendSig->length);
        UA_ByteString dataToSignExt = {extLen, ext};
        retval = sp->asymSignatureAlgorithm.sign(sp, cc, &dataToSignExt, &signature);
        UA_free(ext);
    } else {
        const UA_ByteString dataToSign = {preSignLength, buf->data};
        retval = sp->asymSignatureAlgorithm.sign(sp, cc, &dataToSign, &signature);
        /* First-OPN client side: remember the just-computed request
         * signature. The verify path on the client will use it to
         * extend the response body. */
        if(retval == UA_STATUSCODE_GOOD && firstOPN && signature.length > 0) {
            UA_StatusCode clip =
                UA_ByteString_copy(&signature, &channel->firstRequestSignature);
            if(clip != UA_STATUSCODE_GOOD)
                retval = clip;
        }
    }

    UA_CHECK_STATUS(retval, return retval);

    /* Server, first OPN response (appendSig != NULL): the just-computed
     * signature is the ChannelThumbprint - capture it (preserved across renewals
     * to bind the session SignatureData) and release the consumed request
     * signature. (The client stored its request signature above; that copy is
     * released later by the OPN-response verify.) */
    if(appendSig != NULL) {
        UA_StatusCode tp = UA_ByteString_copy(&signature, &channel->channelThumbprint);
        UA_CHECK_STATUS(tp, return tp);
        UA_ByteString_clear(&channel->firstRequestSignature);
    }

    /* Specification part 6, 6.7.4: The OpenSecureChannel Messages are
     * signed and encrypted if the SecurityMode is not None (even if the
     * SecurityMode is SignOnly). */
    size_t unencrypted_length =
        UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength;
    UA_ByteString dataToEncrypt =
        {totalLength - unencrypted_length, &buf->data[unencrypted_length]};
    return sp->asymEncryptionAlgorithm.encrypt(sp, cc, &dataToEncrypt);
}

/**************************/
/* Send Symmetric Message */
/**************************/

UA_StatusCode
signAndEncryptSym(UA_MessageContext *messageContext,
                  size_t preSigLength, size_t totalLength) {
    const UA_SecureChannel *channel = messageContext->channel;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
        return UA_STATUSCODE_GOOD;

    const UA_SecurityPolicy *sp = channel->securityPolicy;
    void *cc = channel->channelContext;

    /* For AEAD policies (ChaCha20-Poly1305), set the message security
     * parameters for nonce masking. Then let the encrypt callback handle
     * both authentication and encryption. */
    if(UA_SecurityPolicy_isAead(sp)) {
        /* Set AEAD parameters: tokenId, previous seqNo, AAD */
        if(sp->setMessageSecurityParameters) {
            UA_ByteString aad;
            aad.data = messageContext->messageBuffer.data;
            aad.length = UA_SECURECHANNEL_CHANNELHEADER_LENGTH +
                         UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH;
            /* The AEAD nonce is masked with the PREVIOUS sequence number: the
             * receiver masks with its receiveSequenceNumber, which is still the
             * prior chunk's number at decrypt time (incremented only after
             * decryption). sendSequenceNumber is the post-increment counter, so
             * the value just emitted is (sendSequenceNumber - 1) and the
             * previous one is (sendSequenceNumber - 2). ECC_AEAD always uses the
             * non-legacy counter (first emitted number is 0). */
            UA_UInt32 prevSeqNo = channel->sendSequenceNumber >= 2 ?
                (UA_UInt32)(channel->sendSequenceNumber - 2) : 0;
            UA_StatusCode res = sp->setMessageSecurityParameters(
                sp, cc, channel->securityToken.tokenId, prevSeqNo, &aad);
            UA_CHECK_STATUS(res, return res);
        }

        if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
            /* Full AEAD: encrypt + compute auth tag. Data includes
             * the 16-byte tag space at the end. */
            UA_ByteString dataToProcess;
            dataToProcess.data = messageContext->messageBuffer.data +
                UA_SECURECHANNEL_CHANNELHEADER_LENGTH +
                UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH;
            dataToProcess.length = totalLength -
                (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +
                 UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH);
            return sp->symEncryptionAlgorithm.encrypt(sp, cc, &dataToProcess);
        }

        /* Sign-only: Compute Poly1305 auth tag */
        UA_ByteString dataToSign = messageContext->messageBuffer;
        dataToSign.length = preSigLength;
        UA_ByteString signature;
        signature.length =
            sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc);
        signature.data = messageContext->buf_pos;
        return sp->symSignatureAlgorithm.
            sign(sp, cc, &dataToSign, &signature);
    }

    /* Sign */
    UA_ByteString dataToSign = messageContext->messageBuffer;
    dataToSign.length = preSigLength;
    UA_ByteString signature;
    signature.length =
        sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc);
    signature.data = messageContext->buf_pos;
    UA_StatusCode res = sp->symSignatureAlgorithm.
        sign(sp, cc, &dataToSign, &signature);
    UA_CHECK_STATUS(res, return res);

    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    /* Encrypt */
    UA_ByteString dataToEncrypt;
    dataToEncrypt.data = messageContext->messageBuffer.data +
        UA_SECURECHANNEL_CHANNELHEADER_LENGTH +
        UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH;
    dataToEncrypt.length = totalLength -
        (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +
         UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH);
    return sp->symEncryptionAlgorithm.encrypt(sp, cc, &dataToEncrypt);
}

void
setBufPos(UA_MessageContext *mc) {
    /* Forward the data pointer so that the payload is encoded after the message
     * header. This has to be a symmetric message because OPN (with asymmetric
     * encryption) does not support chunking. */
    mc->buf_pos = &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH];
    mc->buf_end = &mc->messageBuffer.data[mc->messageBuffer.length];

    if(mc->channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
        return;

    const UA_SecureChannel *channel = mc->channel;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    void *cc = channel->channelContext;

    /* For AEAD (ChaCha20-Poly1305): no padding, no block alignment.
     * Only reserve space for the authentication tag (signature size). */
    if(UA_SecurityPolicy_isAead(sp)) {
        size_t sigsize =
            sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc);
        mc->buf_end -= sigsize;
        UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                             "Prepare an AEAD symmetric message buffer of length %lu "
                             "with a usable maximum payload length of %lu",
                             (long unsigned)mc->messageBuffer.length,
                             (long unsigned)((uintptr_t)mc->buf_end -
                                             (uintptr_t)mc->messageBuffer.data));
        return;
    }

    size_t sigsize =
        sp->symSignatureAlgorithm.getLocalSignatureSize(sp, cc);
    size_t plainBlockSize =
        sp->symEncryptionAlgorithm.getRemotePlainTextBlockSize(sp, cc);

    /* Assuming that for symmetric encryption the plainTextBlockSize ==
     * cypherTextBlockSize. For symmetric encryption the remote/local block
     * sizes are identical. */
    UA_assert(sp->symEncryptionAlgorithm.getRemoteBlockSize(sp, cc) == plainBlockSize);

    /* Leave enough space for the signature and padding */
    mc->buf_end -= sigsize;
    UA_assert(plainBlockSize > 0);
    mc->buf_end -= mc->messageBuffer.length % plainBlockSize;

    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        /* Reserve space for the padding bytes */
        UA_Boolean extraPadding =
            (sp->symEncryptionAlgorithm.getRemoteKeyLength(sp, cc) > 2048);
        mc->buf_end -= (UA_LIKELY(!extraPadding)) ? 1 : 2;
    }

    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                         "Prepare a symmetric message buffer of length %lu "
                         "with a usable maximum payload length of %lu",
                         (long unsigned)mc->messageBuffer.length,
                         (long unsigned)((uintptr_t)mc->buf_end -
                                         (uintptr_t)mc->messageBuffer.data));
}

/****************************/
/* Process a received Chunk */
/****************************/

static size_t
decodePadding(const UA_SecureChannel *channel,
              const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
              const UA_ByteString *chunk, size_t sigsize) {
    /* Read the byte with the padding size */
    size_t paddingSize = chunk->data[chunk->length - sigsize - 1];

    /* Extra padding size */
    if(encryptionAlgorithm->getLocalKeyLength(channel->securityPolicy,
                                              channel->channelContext) > 2048) {
        paddingSize <<= 8u;
        paddingSize += chunk->data[chunk->length - sigsize - 2];
        paddingSize += 1; /* Extra padding byte itself */
    }

    /* Add one since the paddingSize byte itself needs to be removed as well */
    return paddingSize + 1;
}

/* Sets the payload to a pointer inside the chunk buffer. Returns the requestId
 * and the sequenceNumber */
UA_StatusCode
decryptAndVerifyChunk(UA_SecureChannel *channel,
                      const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm,
                      const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
                      UA_MessageType messageType, UA_ByteString *chunk,
                      size_t offset) {
    UA_SecurityPolicy *sp = channel->securityPolicy;
    void *cc = channel->channelContext;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* AEAD path (ChaCha20-Poly1305): the decrypt callback handles both
     * decryption and authentication tag verification in one step. */
    if(UA_SecurityPolicy_isAead(sp) &&
       messageType != UA_MESSAGETYPE_OPN) {

        /* Set AEAD parameters before decrypt/verify. The masked nonce is keyed
         * on the TokenId of *this* message, which is taken from the chunk's
         * symmetric SecurityHeader (right after the 12-byte channel header) and
         * not from channel->securityToken: during a token rollover the peer may
         * still secure messages with the old token (Part 4 §5.5.2) while the
         * channel already holds the new token. Using the wrong TokenId here
         * makes the AEAD tag verification fail. */
        if(sp->setMessageSecurityParameters) {
            UA_ByteString aad = {offset, chunk->data};
            size_t tokenOffset = UA_SECURECHANNEL_CHANNELHEADER_LENGTH;
            UA_UInt32 msgTokenId = channel->securityToken.tokenId;
            if(offset >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH)
                UA_UInt32_decodeBinary(chunk, &tokenOffset, &msgTokenId);
            res = sp->setMessageSecurityParameters(
                sp, cc, msgTokenId,
                channel->receiveSequenceNumber, &aad);
            UA_CHECK_STATUS(res, return res);
        }

        if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
            /* Full AEAD decrypt + verify. The decrypt callback processes
             * the data including the 16-byte auth tag at the end. On
             * success, it reduces cipher.length by the tag size. */
            UA_ByteString cipher = {chunk->length - offset, chunk->data + offset};
            res = encryptionAlgorithm->decrypt(sp, cc, &cipher);
            UA_CHECK_STATUS(res,
                UA_LOG_WARNING_CHANNEL(sp->logger, channel,
                                       "AEAD decryption/verification failed");
                return res);
            chunk->length = cipher.length + offset;
        } else if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN) {
            /* Sign-only: verify the auth tag without decryption */
            size_t sigsize = signatureAlgorithm->getRemoteSignatureSize(sp, cc);
            UA_CHECK(sigsize < chunk->length,
                     return UA_STATUSCODE_BADSECURITYCHECKSFAILED);
            const UA_ByteString content = {chunk->length - sigsize, chunk->data};
            const UA_ByteString sig = {sigsize, chunk->data + chunk->length - sigsize};
            res = signatureAlgorithm->verify(sp, cc, &content, &sig);
            UA_CHECK_STATUS(res,
                UA_LOG_WARNING_CHANNEL(sp->logger, channel,
                                       "AEAD signature verification failed");
                return res);
            chunk->length -= sigsize;
        }

        /* Verify the content length */
        UA_CHECK(offset + 9 < chunk->length,
                 UA_LOG_ERROR_CHANNEL(sp->logger, channel,
                                      "AEAD message too short");
                 return UA_STATUSCODE_BADSECURITYCHECKSFAILED);
        return UA_STATUSCODE_GOOD;
    }

    /* Decrypt the chunk */
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
       messageType == UA_MESSAGETYPE_OPN) {
        UA_ByteString cipher = {chunk->length - offset, chunk->data + offset};
        res = encryptionAlgorithm->decrypt(sp, cc, &cipher);
        UA_CHECK_STATUS(res, return res);
        chunk->length = cipher.length + offset;
    }

    /* Does the message have a signature? */
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
       messageType != UA_MESSAGETYPE_OPN)
        return UA_STATUSCODE_GOOD;

    /* Verify the chunk signature */
    UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Verifying chunk signature");
    size_t sigsize = signatureAlgorithm->getRemoteSignatureSize(sp, cc);
    UA_CHECK(sigsize < chunk->length, return UA_STATUSCODE_BADSECURITYCHECKSFAILED);
    const UA_ByteString content = {chunk->length - sigsize, chunk->data};
    const UA_ByteString sig = {sigsize, chunk->data + chunk->length - sigsize};

    /* OPC UA Part 6 v1.05.07 §6.7.5 "ChannelThumbprint" (only for the first
     * OPN exchange and only for SecurityPolicies with
     * secureChannelEnhancements = true). For the *first* OPN only:
     *
     *   Server side (verify an incoming OPN request): the request
     *   signature is unknown to the server until it has been
     *   verified. Capture the bytes now (BEFORE stripping) so the
     *   sign path of the OPN response can append them.
     *
     *   Client side (verify the OPN response): the client's own
     *   request signature was stored in firstRequestSignature when
     *   the request was sent. Extend the verify content with it.
     *
     * For OPN *renewals* the firstRequestSignature is empty (it was
     * cleared by the first exchange) and the normal v1.05.06 verify
     * path is used. */
    UA_ByteString verifyContent = content;
    UA_Byte *extendedBuf = NULL;
    UA_Boolean capturedIncoming = false;
    /* First-OPN only (channelThumbprint empty). On renewals neither capture nor
     * extend - the v1.05.06 verify path is used. */
    UA_Boolean firstOPN = (channel->enhancedSecurity &&
                           messageType == UA_MESSAGETYPE_OPN &&
                           channel->channelThumbprint.length == 0);
    if(firstOPN) {
        if(channel->firstRequestSignature.length == 0) {
            /* First-OPN, receiving side: capture the incoming signature.
             * The sign path of the response will consume it. */
            UA_StatusCode clip = UA_ByteString_copy(&sig, &channel->firstRequestSignature);
            UA_CHECK_STATUS(clip, return clip);
            capturedIncoming = true;
        } else {
            /* Verifying the OPN response: extend the content. */
            extendedBuf = (UA_Byte*)UA_malloc(
                content.length + channel->firstRequestSignature.length);
            if(!extendedBuf) {
                UA_ByteString_clear(&channel->firstRequestSignature);
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            memcpy(extendedBuf, content.data, content.length);
            memcpy(extendedBuf + content.length,
                   channel->firstRequestSignature.data,
                   channel->firstRequestSignature.length);
            verifyContent.data = extendedBuf;
            verifyContent.length =
                content.length + channel->firstRequestSignature.length;
        }
    }

    res = signatureAlgorithm->verify(sp, cc, &verifyContent, &sig);
    UA_free(extendedBuf);

    /* Single-use: if we just consumed the stored signature (client side
     * verifying the response), clear it. If we just captured the
     * incoming signature (server side verifying the request), keep
     * it — the sign path of the response will use and then clear it. */
    if(firstOPN && !capturedIncoming) {
        UA_ByteString_clear(&channel->firstRequestSignature);
    }

    UA_CHECK_STATUS(res, UA_LOG_WARNING_CHANNEL(sp->logger, channel,
                                                "Could not verify the signature");
                    return res);

    /* OPC UA Part 6 v1.05.07 ChannelThumbprint: on the client, the
     * verified first-OPN *response* signature (sig) is the
     * ChannelThumbprint. capturedIncoming is false only on the
     * client response-verify path. Capture once, preserve across
     * renewals; binds the session SignatureData to this channel. */
    if(channel->enhancedSecurity && messageType == UA_MESSAGETYPE_OPN &&
       !capturedIncoming && channel->channelThumbprint.length == 0) {
        UA_StatusCode tp = UA_ByteString_copy(&sig, &channel->channelThumbprint);
        UA_CHECK_STATUS(tp, return tp);
    }

    /* Compute the padding if the payload is encrypted (not ECC policy) */
    size_t padSize = 0;
    if((messageType != UA_MESSAGETYPE_OPN &&
        channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) ||
       (messageType == UA_MESSAGETYPE_OPN &&
        sp->policyType == UA_SECURITYPOLICYTYPE_RSA)) {
        padSize = decodePadding(channel, encryptionAlgorithm, chunk, sigsize);
        UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Calculated padding size to be %lu",
                             (long unsigned)padSize);
    }

    /* Verify the content length. The encrypted payload has to be at least 9
     * bytes long: 8 byte for the SequenceHeader and one byte for the actual
     * message */
    UA_CHECK(offset + padSize + sigsize + 9 < chunk->length,
             UA_LOG_ERROR_CHANNEL(sp->logger, channel, "Impossible padding value");
             return UA_STATUSCODE_BADSECURITYCHECKSFAILED);

    /* Hide the signature and padding */
    chunk->length -= (sigsize + padSize);
    return UA_STATUSCODE_GOOD;
}

/* The certificate in the header is verified via the configured PKI plugin as
 * certificateVerification.verifyCertificate(...). We cannot do it here because
 * the client/server context is needed. */
UA_StatusCode
checkAsymHeader(UA_SecureChannel *channel,
                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    if(!UA_String_equal(&sp->policyUri, &asymHeader->securityPolicyUri))
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    return sp->compareCertThumbprint(sp, &asymHeader->receiverCertificateThumbprint);
}

UA_StatusCode
checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId,
               UA_DateTime nowMonotonic) {
    UA_SecurityPolicy *sp = channel->securityPolicy;
    (void)sp;

    /* If no match, try to revolve to the next token after a
     * RenewSecureChannel */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_ChannelSecurityToken *token = &channel->securityToken;
    switch(channel->renewState) {
    case UA_SECURECHANNELRENEWSTATE_NORMAL:
    case UA_SECURECHANNELRENEWSTATE_SENT:
    default:
        break;

    case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER:
        /* Old token still in use */
        if(tokenId == channel->securityToken.tokenId)
            break;

        /* Not the new token */
        UA_CHECK(tokenId == channel->altSecurityToken.tokenId,
                 UA_LOG_ERROR_CHANNEL(sp->logger, channel, "Unknown SecurityToken");
                 return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN);

        /* Roll over to the new token, generate new local and remote keys */
        channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
        channel->securityToken = channel->altSecurityToken;
        UA_ChannelSecurityToken_init(&channel->altSecurityToken);
        retval |= UA_SecureChannel_generateLocalKeys(channel);
        retval |= generateRemoteKeys(channel);
        UA_CHECK_STATUS(retval, return retval);
        break;

    case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT:
        /* The server is still using the old token. That's okay. */
        if(tokenId == channel->altSecurityToken.tokenId) {
            token = &channel->altSecurityToken;
            break;
        }

        /* Not the new token */
        UA_CHECK(tokenId == channel->securityToken.tokenId,
                 UA_LOG_ERROR_CHANNEL(sp->logger, channel, "Unknown SecurityToken");
                 return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN);

        /* The remote server uses the new token for the first time. Delete the
         * old token and roll the remote key over. The local key already uses
         * the nonce pair from the last OPN exchange. */
        channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
        UA_ChannelSecurityToken_init(&channel->altSecurityToken);
        retval = generateRemoteKeys(channel);
        UA_CHECK_STATUS(retval, return retval);
    }

    UA_DateTime timeout = token->createdAt + (token->revisedLifetime * UA_DATETIME_MSEC);
    if(channel->state == UA_SECURECHANNELSTATE_OPEN && timeout < nowMonotonic) {
        UA_LOG_ERROR_CHANNEL(sp->logger, channel, "SecurityToken timed out");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_TIMEOUT);
        return UA_STATUSCODE_BADSECURECHANNELCLOSED;
    }

    return UA_STATUSCODE_GOOD;
}

UA_Boolean
UA_SecureChannel_checkTimeout(UA_SecureChannel *channel, UA_DateTime nowMonotonic) {
    /* Compute the timeout date of the SecurityToken */
    UA_DateTime timeout = channel->securityToken.createdAt +
        (UA_DateTime)(channel->securityToken.revisedLifetime * UA_DATETIME_MSEC);

    /* The token has timed out. Try to do the token revolving now instead of
     * shutting the channel down.
     *
     * Part 4, 5.5.2 says: Servers shall use the existing SecurityToken to
     * secure outgoing Messages until the SecurityToken expires or the
     * Server receives a Message secured with a new SecurityToken.*/
    if(timeout < nowMonotonic &&
       channel->renewState == UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER) {
        /* Revolve the token manually. This is otherwise done in checkSymHeader. */
        channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
        channel->securityToken = channel->altSecurityToken;
        UA_ChannelSecurityToken_init(&channel->altSecurityToken);
        UA_SecureChannel_generateLocalKeys(channel);
        generateRemoteKeys(channel);

        /* Use the timeout of the new SecurityToken */
        timeout = channel->securityToken.createdAt +
            (UA_DateTime)(channel->securityToken.revisedLifetime * UA_DATETIME_MSEC);
    }

    return (timeout < nowMonotonic);
}

/**** amalgamated original file "/src/server/ua_session.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */

#ifdef UA_ENABLE_SUBSCRIPTIONS
#endif

void UA_Session_init(UA_Session *session) {
    memset(session, 0, sizeof(UA_Session));
    session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    SIMPLEQ_INIT(&session->responseQueue);
    TAILQ_INIT(&session->subscriptions);
#endif
}

void UA_Session_clear(UA_Session *session, UA_Server* server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Remove all Subscriptions. This may send out remaining publish
     * responses. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_Subscription *sub, *tempsub;
    TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, tempsub) {
        UA_Subscription_delete(server, sub);
    }
#endif

#ifdef UA_ENABLE_DIAGNOSTICS
    deleteNode(server, session->sessionId, true);
#endif

    UA_Session_detachFromSecureChannel(server, session);
    UA_ApplicationDescription_clear(&session->clientDescription);
    UA_ByteString_clear(&session->clientCertificate);
    UA_NodeId_clear(&session->authenticationToken);
    UA_String_clear(&session->clientUserIdOfSession);
    UA_NodeId_clear(&session->sessionId);
    UA_String_clear(&session->sessionName);
    UA_ByteString_clear(&session->serverNonce);
    UA_ByteString_clear(&session->clientNonce);
    struct ContinuationPoint *cp, *next = session->continuationPoints;
    while((cp = next)) {
        next = ContinuationPoint_clear(cp);
        UA_free(cp);
    }
    session->continuationPoints = NULL;
    session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS;

    UA_KeyValueMap_clear(&session->attributes);

    UA_Array_delete(session->localeIds, session->localeIdsSize,
                    &UA_TYPES[UA_TYPES_STRING]);
    session->localeIds = NULL;
    session->localeIdsSize = 0;

#ifdef UA_ENABLE_DIAGNOSTICS
    UA_SessionDiagnosticsDataType_clear(&session->diagnostics);
    UA_SessionSecurityDiagnosticsDataType_clear(&session->securityDiagnostics);
#endif

    if(session->sessionSp && session->sessionSpContext) {
        session->sessionSp->
            deleteChannelContext(session->sessionSp, session->sessionSpContext);
        session->sessionSp = NULL;
        session->sessionSpContext = NULL;
    }
}

void
UA_Session_attachToSecureChannel(UA_Server *server, UA_Session *session,
                                 UA_SecureChannel *channel) {
    /* Ensure the Session is not attached to another SecureChannel */
    UA_Session_detachFromSecureChannel(server, session);

    /* Add to singly-linked list */
    session->next = channel->sessions;
    channel->sessions = session;

    /* Add backpointer */
    session->channel = channel;
}

void
UA_Session_detachFromSecureChannel(UA_Server *server, UA_Session *session) {
    /* Clean up the response queue. Their RequestId is bound to the
     * SecureChannel so they cannot be reused. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_PublishResponseEntry *pre;
    while((pre = UA_Session_dequeuePublishReq(session))) {
        UA_PublishResponse_clear(&pre->response);
        UA_free(pre);
    }
#endif

    /* Remove from singly-linked list */
    UA_SecureChannel *channel = session->channel;
    if(!channel)
        return;

    if(channel->sessions == session) {
        channel->sessions = session->next;
    } else {
        UA_Session *elm =  channel->sessions;
        while(elm->next != session)
            elm = elm->next;
        elm->next = session->next;
    }

    /* Reset the backpointer */
    session->channel = NULL;

    /* Notify the application */
    notifySession(server, session,
                  UA_APPLICATIONNOTIFICATIONTYPE_SESSION_DEACTIVATED);
}

UA_StatusCode
UA_Session_generateNonce(UA_Session *session) {
    UA_SecureChannel *channel = session->channel;
    if(!channel || !channel->securityPolicy)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The nonce needs to be between 32 and 128 byte.
     * The #Nonce SecurityPolicy might not do that. */
    UA_SecurityPolicy *sp = channel->securityPolicy;
    void *spC = channel->channelContext;
    if(session->sessionSp && session->sessionSpContext) {
        sp = session->sessionSp;
        spC = session->sessionSpContext;
    }

    /* The session ServerNonce is a 32-byte application nonce. This is
     * independent of the SecurityPolicy's SecureChannel nonce length (for ECC
     * policies that is the 64-byte ephemeral key, which is NOT the session
     * nonce). */
    size_t nonceLength = 32;

    /* Is the length of the previous nonce correct? */
    if(session->serverNonce.length != nonceLength) {
        UA_ByteString_clear(&session->serverNonce);
        UA_StatusCode res =
            UA_ByteString_allocBuffer(&session->serverNonce, nonceLength);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Generate plain random data. Ensure data[0] is not the 'e' of the "eph"
     * trigger that some ECC policies use to produce an ephemeral key. */
    session->serverNonce.data[0] = 0;
    return sp->generateNonce(sp, spC, &session->serverNonce);
}

void
UA_Session_updateLifetime(UA_Session *session, UA_DateTime now,
                          UA_DateTime nowMonotonic) {
    session->validTill = nowMonotonic +
        (UA_DateTime)(session->timeout * UA_DATETIME_MSEC);
#ifdef UA_ENABLE_DIAGNOSTICS
    session->diagnostics.clientLastContactTime = now;
#endif
}

#ifdef UA_ENABLE_SUBSCRIPTIONS

void
UA_Session_attachSubscription(UA_Session *session, UA_Subscription *sub) {
    /* Attach to the session */
    sub->session = session;

    /* Increase the count */
    session->subscriptionsSize++;

    /* Increase the number of outstanding retransmissions */
    session->totalRetransmissionQueueSize += sub->retransmissionQueueSize;

    /* Insert at the end of the subscriptions of the same priority / just before
     * the subscriptions with the next lower priority. */
    UA_Subscription *after = NULL;
    TAILQ_FOREACH(after, &session->subscriptions, sessionListEntry) {
        if(after->priority < sub->priority) {
            TAILQ_INSERT_BEFORE(after, sub, sessionListEntry);
            return;
        }
    }
    TAILQ_INSERT_TAIL(&session->subscriptions, sub, sessionListEntry);
}

void
UA_Session_detachSubscription(UA_Server *server, UA_Session *session,
                              UA_Subscription *sub, UA_Boolean releasePublishResponses) {
    /* Detach from the session */
    sub->session = NULL;
    TAILQ_REMOVE(&session->subscriptions, sub, sessionListEntry);

    /* Reduce the count */
    UA_assert(session->subscriptionsSize > 0);
    session->subscriptionsSize--;

    /* Reduce the number of outstanding retransmissions */
    session->totalRetransmissionQueueSize -= sub->retransmissionQueueSize;

    /* Send remaining publish responses if the last subscription was removed */
    if(!releasePublishResponses || !TAILQ_EMPTY(&session->subscriptions))
        return;
    UA_PublishResponseEntry *pre;
    while((pre = UA_Session_dequeuePublishReq(session))) {
        UA_PublishResponse *response = &pre->response;
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION;
        sendResponse(server, session->channel, pre->requestId,
                     (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
        UA_PublishResponse_clear(response);
        UA_free(pre);
    }
}

UA_Subscription *
UA_Session_getSubscriptionById(UA_Session *session, UA_UInt32 subscriptionId) {
    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        /* Prevent lookup of subscriptions that are to be deleted with a statuschange */
        if(sub->statusChange != UA_STATUSCODE_GOOD)
            continue;
        if(sub->subscriptionId == subscriptionId)
            break;
    }
    return sub;
}

UA_Subscription *
getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId) {
    UA_Subscription *sub;
    LIST_FOREACH(sub, &server->subscriptions, serverListEntry) {
        /* Prevent lookup of subscriptions that are to be deleted with a statuschange */
        if(sub->statusChange != UA_STATUSCODE_GOOD)
            continue;
        if(sub->subscriptionId == subscriptionId)
            break;
    }
    return sub;
}

UA_PublishResponseEntry*
UA_Session_dequeuePublishReq(UA_Session *session) {
    UA_PublishResponseEntry *entry = SIMPLEQ_FIRST(&session->responseQueue);
    if(entry) {
        SIMPLEQ_REMOVE_HEAD(&session->responseQueue, listEntry);
        session->responseQueueSize--;
    }
    return entry;
}

void
UA_Session_queuePublishReq(UA_Session *session, UA_PublishResponseEntry* entry,
                           UA_Boolean head) {
    if(!head)
        SIMPLEQ_INSERT_TAIL(&session->responseQueue, entry, listEntry);
    else
        SIMPLEQ_INSERT_HEAD(&session->responseQueue, entry, listEntry);
    session->responseQueueSize++;
}

#endif

/* Session Handling */

UA_StatusCode
UA_Server_closeSession(UA_Server *server, const UA_NodeId *sessionId) {
    lockServer(server);
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        unlockServer(server);
        return UA_STATUSCODE_BADSESSIONIDINVALID;
    }
    UA_Session_remove(server, session, UA_SHUTDOWNREASON_CLOSE);
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

/* Session Attributes */

#define UA_PROTECTEDATTRIBUTESSIZE 4
static const UA_QualifiedName protectedAttributes[UA_PROTECTEDATTRIBUTESSIZE] = {
    {0, UA_STRING_STATIC("localeIds")},
    {0, UA_STRING_STATIC("clientDescription")},
    {0, UA_STRING_STATIC("sessionName")},
    {0, UA_STRING_STATIC("clientUserId")}
};

static UA_Boolean
protectedAttribute(const UA_QualifiedName key) {
    for(size_t i = 0; i < UA_PROTECTEDATTRIBUTESSIZE; i++) {
        if(UA_QualifiedName_equal(&key, &protectedAttributes[i]))
            return true;
    }
    return false;
}

UA_StatusCode
UA_Server_setSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                              const UA_QualifiedName key, const UA_Variant *value) {
    if(protectedAttribute(key))
        return UA_STATUSCODE_BADNOTWRITABLE;
    lockServer(server);
    UA_Session *session = getSessionById(server, sessionId);
    UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID;
    if(session)
        res = UA_KeyValueMap_set(&session->attributes, key, value);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_deleteSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                                 const UA_QualifiedName key) {
    if(protectedAttribute(key))
        return UA_STATUSCODE_BADNOTWRITABLE;
    lockServer(server);
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        unlockServer(server);
        return UA_STATUSCODE_BADSESSIONIDINVALID;
    }
    UA_StatusCode res = UA_KeyValueMap_remove(&session->attributes, key);
    unlockServer(server);
    return res;
}

static UA_StatusCode
getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                    const UA_QualifiedName key, UA_Variant *outValue,
                    UA_Boolean copy) {
    if(!outValue)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_Session *session = getSessionById(server, sessionId);
    if(!session)
        return UA_STATUSCODE_BADSESSIONIDINVALID;

    const UA_Variant *attr;
    UA_Variant localAttr;

    if(UA_QualifiedName_equal(&key, &protectedAttributes[0])) {
        /* Return LocaleIds */
        UA_Variant_setArray(&localAttr, session->localeIds,
                            session->localeIdsSize, &UA_TYPES[UA_TYPES_STRING]);
        attr = &localAttr;
    } else if(UA_QualifiedName_equal(&key, &protectedAttributes[1])) {
        /* Return client description */
        UA_Variant_setScalar(&localAttr, &session->clientDescription,
                             &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
        attr = &localAttr;
    } else if(UA_QualifiedName_equal(&key, &protectedAttributes[2])) {
        /* Return session name */
        UA_Variant_setScalar(&localAttr, &session->sessionName,
                             &UA_TYPES[UA_TYPES_STRING]);
        attr = &localAttr;
    } else if(UA_QualifiedName_equal(&key, &protectedAttributes[3])) {
        /* Return client user id */
        UA_Variant_setScalar(&localAttr, &session->clientUserIdOfSession,
                             &UA_TYPES[UA_TYPES_STRING]);
        attr = &localAttr;
    } else {
        /* Get from the actual key-value list */
        attr = UA_KeyValueMap_get(&session->attributes, key);
        if(!attr)
            return UA_STATUSCODE_BADNOTFOUND;
    }

    if(copy)
        return UA_Variant_copy(attr, outValue);

    *outValue = *attr;
    outValue->storageType = UA_VARIANT_DATA_NODELETE;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                              const UA_QualifiedName key, UA_Variant *outValue) {
    lockServer(server);
    UA_StatusCode res = getSessionAttribute(server, sessionId, key, outValue, false);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getSessionAttributeCopy(UA_Server *server, const UA_NodeId *sessionId,
                                  const UA_QualifiedName key, UA_Variant *outValue) {
    lockServer(server);
    UA_StatusCode res = getSessionAttribute(server, sessionId, key, outValue, true);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getSessionAttribute_scalar(UA_Server *server,
                                     const UA_NodeId *sessionId,
                                     const UA_QualifiedName key,
                                     const UA_DataType *type,
                                     void *outValue) {
    lockServer(server);

    UA_Variant attr;
    UA_StatusCode res = getSessionAttribute(server, sessionId, key, &attr, false);
    if(res != UA_STATUSCODE_GOOD) {
        unlockServer(server);
        return res;
    }

    if(!UA_Variant_hasScalarType(&attr, type)) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    memcpy(outValue, attr.data, type->memSize);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/src/server/ua_nodes.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015, 2017 (c) Florian Palm
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 */


/*********************/
/* ReferenceType Set */
/*********************/

#define UA_REFTYPES_ALL_MASK (~(UA_UInt32)0)
#define UA_REFTYPES_ALL_MASK2 UA_REFTYPES_ALL_MASK, UA_REFTYPES_ALL_MASK
#define UA_REFTYPES_ALL_MASK4 UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK2
#if UA_REFERENCETYPESET_MAX / 32 > 8
# error Adjust macros to support than 256 reference types
#elif UA_REFERENCETYPESET_MAX / 32 == 8
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK4
#elif UA_REFERENCETYPESET_MAX / 32 == 7
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK
#elif UA_REFERENCETYPESET_MAX / 32 == 6
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK2
#elif UA_REFERENCETYPESET_MAX / 32 == 5
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK
#elif UA_REFERENCETYPESET_MAX / 32 == 4
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4
#elif UA_REFERENCETYPESET_MAX / 32 == 3
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK
#elif UA_REFERENCETYPESET_MAX / 32 == 2
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK2
#else
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK
#endif

const UA_ReferenceTypeSet UA_REFERENCETYPESET_NONE = {{0}};
const UA_ReferenceTypeSet UA_REFERENCETYPESET_ALL = {{UA_REFTYPES_ALL_ARRAY}};

/*****************/
/* Node Pointers */
/*****************/

#define UA_NODEPOINTER_MASK 0x03
#define UA_NODEPOINTER_TAG_IMMEDIATE 0x00
#define UA_NODEPOINTER_TAG_NODEID 0x01
#define UA_NODEPOINTER_TAG_EXPANDEDNODEID 0x02
#define UA_NODEPOINTER_TAG_NODE 0x03

void
UA_NodePointer_clear(UA_NodePointer *np) {
    switch(np->immediate & UA_NODEPOINTER_MASK) {
    case UA_NODEPOINTER_TAG_NODEID:
        np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
        UA_NodeId_delete((UA_NodeId*)(uintptr_t)np->id);
        break;
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
        np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
        UA_ExpandedNodeId_delete((UA_ExpandedNodeId*)(uintptr_t)
                                 np->expandedId);
        break;
    default:
        break;
    }
    UA_NodePointer_init(np);
}

UA_StatusCode
UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_Byte tag = in.immediate & UA_NODEPOINTER_MASK;
    in.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    switch(tag) {
    case UA_NODEPOINTER_TAG_NODE:
        in.id = &in.node->nodeId;
        goto nodeid; /* fallthrough */
    case UA_NODEPOINTER_TAG_NODEID:
    nodeid:
        out->id = UA_NodeId_new();
        if(!out->id)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_NodeId_copy(in.id, (UA_NodeId*)(uintptr_t)out->id);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free((void*)out->immediate);
            out->immediate = 0;
            break;
        }
        out->immediate |= UA_NODEPOINTER_TAG_NODEID;
        break;
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
        out->expandedId = UA_ExpandedNodeId_new();
        if(!out->expandedId)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_ExpandedNodeId_copy(in.expandedId,
                                     (UA_ExpandedNodeId*)(uintptr_t)
                                     out->expandedId);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free((void*)out->immediate);
            out->immediate = 0;
            break;
        }
        out->immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID;
        break;
    default:
    case UA_NODEPOINTER_TAG_IMMEDIATE:
        *out = in;
        break;
    }
    return res;
}

UA_Boolean
UA_NodePointer_isLocal(UA_NodePointer np) {
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
    return (tag != UA_NODEPOINTER_TAG_EXPANDEDNODEID);
}

UA_Order
UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2) {
    if(p1.immediate == p2.immediate)
        return UA_ORDER_EQ;

    /* Extract the tag and resolve pointers to nodes */
    UA_Byte tag1 = p1.immediate & UA_NODEPOINTER_MASK;
    if(tag1 == UA_NODEPOINTER_TAG_NODE) {
        p1 = UA_NodePointer_fromNodeId(&p1.node->nodeId);
        tag1 = p1.immediate & UA_NODEPOINTER_MASK;
    }
    UA_Byte tag2 = p2.immediate & UA_NODEPOINTER_MASK;
    if(tag2 == UA_NODEPOINTER_TAG_NODE) {
        p2 = UA_NodePointer_fromNodeId(&p2.node->nodeId);
        tag2 = p2.immediate & UA_NODEPOINTER_MASK;
    }

    /* Different tags, cannot be identical */
    if(tag1 != tag2)
        return (tag1 > tag2) ? UA_ORDER_MORE : UA_ORDER_LESS;

    /* Immediate */
    if(UA_LIKELY(tag1 == UA_NODEPOINTER_TAG_IMMEDIATE))
        return (p1.immediate > p2.immediate) ?
            UA_ORDER_MORE : UA_ORDER_LESS;

    /* Compare from pointers */
    p1.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    p2.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    if(tag1 == UA_NODEPOINTER_TAG_EXPANDEDNODEID)
        return UA_ExpandedNodeId_order(p1.expandedId, p2.expandedId);
    return UA_NodeId_order(p1.id, p2.id);
}

UA_NodePointer
UA_NodePointer_fromNodeId(const UA_NodeId *id) {
    UA_NodePointer np;
    if(id->identifierType != UA_NODEIDTYPE_NUMERIC) {
        np.id = id;
        np.immediate |= UA_NODEPOINTER_TAG_NODEID;
        return np;
    }

#if SIZE_MAX > UA_UINT32_MAX
    /* 64bit: 4 Byte for the numeric identifier + 2 Byte for the namespaceIndex
     *        + 1 Byte for the tagging bit (zero) */
    np.immediate  = ((uintptr_t)id->identifier.numeric) << 32;
    np.immediate |= ((uintptr_t)id->namespaceIndex) << 8;
#else
    /* 32bit: 3 Byte for the numeric identifier + 6 Bit for the namespaceIndex
     *        + 2 Bit for the tagging bit (zero) */
    if(id->namespaceIndex < (0x01 << 6) &&
       id->identifier.numeric < (0x01 << 24)) {
        np.immediate  = ((uintptr_t)id->identifier.numeric) << 8;
        np.immediate |= ((uintptr_t)id->namespaceIndex) << 2;
    } else {
        np.id = id;
        np.immediate |= UA_NODEPOINTER_TAG_NODEID;
    }
#endif
    return np;
}

UA_NodeId
UA_NodePointer_toNodeId(UA_NodePointer np) {
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
    np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    switch(tag) {
    case UA_NODEPOINTER_TAG_NODE:
        return np.node->nodeId;
    case UA_NODEPOINTER_TAG_NODEID:
        return *np.id;
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
        return np.expandedId->nodeId;
    default:
    case UA_NODEPOINTER_TAG_IMMEDIATE:
        break;
    }

    UA_NodeId id;
    id.identifierType = UA_NODEIDTYPE_NUMERIC;
#if SIZE_MAX > UA_UINT32_MAX /* 64bit */
    id.namespaceIndex = (UA_UInt16)(np.immediate >> 8);
    id.identifier.numeric = (UA_UInt32)(np.immediate >> 32);
#else                        /* 32bit */
    id.namespaceIndex = ((UA_Byte)np.immediate) >> 2;
    id.identifier.numeric = np.immediate >> 8;
#endif
    return id;
}

UA_NodePointer
UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id) {
    if(!UA_ExpandedNodeId_isLocal(id)) {
        UA_NodePointer np;
        np.expandedId = id;
        np.immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID;
        return np;
    }
    return UA_NodePointer_fromNodeId(&id->nodeId);
}

UA_ExpandedNodeId
UA_NodePointer_toExpandedNodeId(UA_NodePointer np) {
    /* Resolve node pointer to get the NodeId */
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
    if(tag == UA_NODEPOINTER_TAG_NODE) {
        np = UA_NodePointer_fromNodeId(&np.node->nodeId);
        tag = np.immediate & UA_NODEPOINTER_MASK;
    }

    /* ExpandedNodeId, make a shallow copy */
    if(tag == UA_NODEPOINTER_TAG_EXPANDEDNODEID) {
        np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
        return *np.expandedId;
    }

    /* NodeId, either immediate or via a pointer */
    UA_ExpandedNodeId en;
    UA_ExpandedNodeId_init(&en);
    en.nodeId = UA_NodePointer_toNodeId(np);
    return en;
}

/**************/
/* References */
/**************/

static UA_StatusCode
addReferenceTarget(UA_NodeReferenceKind *refs, UA_NodePointer target,
                   UA_UInt32 targetNameHash);

static UA_StatusCode
addReferenceTargetToTree(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
                         UA_UInt32 targetIdHash, UA_UInt32 targetNameHash);

enum ZIP_CMP
cmpRefTargetId(const void *a, const void *b) {
    const UA_ReferenceTargetTreeElem *aa = (const UA_ReferenceTargetTreeElem*)a;
    const UA_ReferenceTargetTreeElem *bb = (const UA_ReferenceTargetTreeElem*)b;
    if(aa->targetIdHash < bb->targetIdHash)
        return ZIP_CMP_LESS;
    if(aa->targetIdHash > bb->targetIdHash)
        return ZIP_CMP_MORE;
    return (enum ZIP_CMP)UA_NodePointer_order(aa->target.targetId,
                                              bb->target.targetId);
}

enum ZIP_CMP
cmpRefTargetName(const void *a, const void *b) {
    const UA_ReferenceTarget *aa = (const UA_ReferenceTarget*)a;
    const UA_ReferenceTarget *bb = (const UA_ReferenceTarget*)b;
    if(aa->targetNameHash == bb->targetNameHash)
        return ZIP_CMP_EQ;
    return (aa->targetNameHash < bb->targetNameHash) ?
        ZIP_CMP_LESS : ZIP_CMP_MORE;
}

/* Move to the array in-order, also deletes the tree elements */
static void
moveTreeToArray(UA_ReferenceTarget *array, size_t *pos,
                UA_ReferenceTargetTreeElem *elem) {
    if(!elem)
        return;
    moveTreeToArray(array, pos, elem->idTreeEntry.left);
    array[*pos] = elem->target;
    (*pos)++;
    moveTreeToArray(array, pos, elem->idTreeEntry.right);
    UA_free(elem);
}

static void *
removeTreeEntry(void *context, UA_ReferenceTargetTreeElem *elem) {
    (void)context;
    UA_NodePointer_clear(&elem->target.targetId);
    UA_free(elem);
    return NULL;
}

UA_StatusCode
UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk) {
    UA_assert(rk->targetsSize > 0);

    if(rk->hasRefTree) {
        /* From tree to array */
        UA_ReferenceTarget *array = (UA_ReferenceTarget*)
            UA_malloc(sizeof(UA_ReferenceTarget) * rk->targetsSize);
        if(!array)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        size_t pos = 0;
        moveTreeToArray(array, &pos, rk->targets.tree.idRoot);
        rk->targets.array = array;
        rk->hasRefTree = false;
        return UA_STATUSCODE_GOOD;
    }

    /* From array to tree */
    UA_NodeReferenceKind newRk = *rk;
    newRk.hasRefTree = true;
    newRk.targets.tree.idRoot = NULL;
    newRk.targets.tree.nameRoot = NULL;
    newRk.targetsSize = 0;
    for(size_t i = 0; i < rk->targetsSize; i++) {
        UA_assert(newRk.hasRefTree == true);
        UA_StatusCode res =
            addReferenceTarget(&newRk, rk->targets.array[i].targetId,
                               rk->targets.array[i].targetNameHash);
        if(res != UA_STATUSCODE_GOOD) {
            ZIP_ITER(UA_ReferenceIdTree,
                     (UA_ReferenceIdTree*)&newRk.targets.tree.idRoot,
                     removeTreeEntry, NULL);
            return res;
        }
    }
    for(size_t i = 0; i < rk->targetsSize; i++)
        UA_NodePointer_clear(&rk->targets.array[i].targetId);
    UA_free(rk->targets.array);
    *rk = newRk;
    return UA_STATUSCODE_GOOD;
}

void *
UA_NodeReferenceKind_iterate(UA_NodeReferenceKind *rk,
                             UA_NodeReferenceKind_iterateCallback callback,
                             void *context) {
    if(rk->hasRefTree)
        return ZIP_ITER(UA_ReferenceIdTree,
                        (UA_ReferenceIdTree*)&rk->targets.tree.idRoot,
                        (UA_ReferenceIdTree_cb)callback, context);
    for(size_t i = 0; i < rk->targetsSize; i++) {
        void *res = callback(context, &rk->targets.array[i]);
        if(res)
            return res;
    }
    return NULL;
}

const UA_ReferenceTarget *
UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk,
                                const UA_ExpandedNodeId *targetId) {
    UA_NodePointer targetP = UA_NodePointer_fromExpandedNodeId(targetId);
    if(rk->hasRefTree) {
        /* Return from the tree */
        UA_ReferenceTargetTreeElem tmpTarget;
        tmpTarget.target.targetId = targetP;
        tmpTarget.targetIdHash = UA_ExpandedNodeId_hash(targetId);
        UA_ReferenceTargetTreeElem *result =
            ZIP_FIND(UA_ReferenceIdTree, (UA_ReferenceIdTree*)
                     (uintptr_t)&rk->targets.tree.idRoot, &tmpTarget);
        if(result)
            return &result->target;
    } else {
        /* Return from the array */
        for(size_t i = 0; i < rk->targetsSize; i++) {
            if(UA_NodePointer_equal(targetP, rk->targets.array[i].targetId))
                return &rk->targets.array[i];
        }
    }
    return NULL;
}

/* General node handling methods. There is no UA_Node_new() method here.
 * Creating nodes is part of the Nodestore layer */

void UA_Node_clear(UA_Node *node) {
    /* Delete references */
    UA_Node_deleteReferences(node);

    /* Delete other head content */
    UA_NodeHead *head = &node->head;
    UA_NodeId_clear(&head->nodeId);
    UA_QualifiedName_clear(&head->browseName);

    UA_LocalizedTextListEntry *lt;

    while((lt = head->displayName)) {
        head->displayName = lt->next;
        UA_LocalizedText_clear(&lt->localizedText);
        UA_free(lt);
    }

    while((lt = head->description)) {
        head->description = lt->next;
        UA_LocalizedText_clear(&lt->localizedText);
        UA_free(lt);
    }

    /* Delete unique content of the nodeclass */
    switch(head->nodeClass) {
    case UA_NODECLASS_OBJECT:
        break;
    case UA_NODECLASS_METHOD:
        break;
    case UA_NODECLASS_OBJECTTYPE:
        break;
    case UA_NODECLASS_VARIABLE:
    case UA_NODECLASS_VARIABLETYPE: {
        UA_VariableNode *p = &node->variableNode;
        UA_NodeId_clear(&p->dataType);
        UA_Array_delete(p->arrayDimensions, p->arrayDimensionsSize,
                        &UA_TYPES[UA_TYPES_INT32]);
        p->arrayDimensions = NULL;
        p->arrayDimensionsSize = 0;
        if(p->valueSourceType == UA_VALUESOURCETYPE_INTERNAL)
            UA_DataValue_clear(&p->valueSource.internal.value);
        break;
    }
    case UA_NODECLASS_REFERENCETYPE: {
        UA_ReferenceTypeNode *p = &node->referenceTypeNode;
        UA_LocalizedText_clear(&p->inverseName);
        break;
    }
    case UA_NODECLASS_DATATYPE:
        break;
    case UA_NODECLASS_VIEW:
        break;
    default:
        break;
    }
}

static UA_StatusCode
UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
    dst->eventNotifier = src->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_CommonVariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
    UA_StatusCode retval =
        UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize,
                      (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    dst->arrayDimensionsSize = src->arrayDimensionsSize;
    retval = UA_NodeId_copy(&src->dataType, &dst->dataType);
    dst->valueRank = src->valueRank;
    dst->valueSourceType = src->valueSourceType;
    dst->valueSource = src->valueSource;
    if(src->valueSourceType == UA_VALUESOURCETYPE_INTERNAL)
        retval |= UA_DataValue_copy(&src->valueSource.internal.value,
                                    &dst->valueSource.internal.value);
    else if(src->valueSourceType == UA_VALUESOURCETYPE_EXTERNAL)
        retval |= UA_DataValue_copy(*src->valueSource.external.value,
                                    &dst->valueSource.internal.value);
    return retval;
}

static UA_StatusCode
UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
    dst->accessLevel = src->accessLevel;
    dst->minimumSamplingInterval = src->minimumSamplingInterval;
    dst->historizing = src->historizing;
    dst->isDynamic = src->isDynamic;
    return UA_CommonVariableNode_copy(src, dst);
}

static UA_StatusCode
UA_VariableTypeNode_copy(const UA_VariableTypeNode *src,
                         UA_VariableTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    return UA_CommonVariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst);
}

static UA_StatusCode
UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
    dst->executable = src->executable;
    dst->method = src->method;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    dst->lifecycle = src->lifecycle;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src,
                          UA_ReferenceTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    dst->symmetric = src->symmetric;
    dst->referenceTypeIndex = src->referenceTypeIndex;
    dst->subTypes = src->subTypes;
    return UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
}

static UA_StatusCode
UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
    dst->containsNoLoops = src->containsNoLoops;
    dst->eventNotifier = src->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static void *
copyTarget(void *context, UA_ReferenceTargetTreeElem *elm) {
    UA_NodeReferenceKind *drefs = (UA_NodeReferenceKind*)context;
    return (void*)(uintptr_t)
        addReferenceTargetToTree(drefs, elm->target.targetId,
                                 elm->targetIdHash,
                                 elm->target.targetNameHash);
}

UA_StatusCode
UA_Node_copy(const UA_Node *src, UA_Node *dst) {
    const UA_NodeHead *srchead = &src->head;
    UA_NodeHead *dsthead = &dst->head;
    if(srchead->nodeClass != dsthead->nodeClass)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy standard content */
    UA_StatusCode retval = UA_NodeId_copy(&srchead->nodeId, &dsthead->nodeId);
    retval |= UA_QualifiedName_copy(&srchead->browseName, &dsthead->browseName);

    /* Copy the display name in several languages */
    for(UA_LocalizedTextListEntry *lt = srchead->displayName; lt != NULL; lt = lt->next) {
        UA_LocalizedTextListEntry *newEntry = (UA_LocalizedTextListEntry *)
            UA_calloc(1, sizeof(UA_LocalizedTextListEntry));
        if(!newEntry) {
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
            break;
        }
        retval |= UA_LocalizedText_copy(&lt->localizedText, &newEntry->localizedText);

        /* Add to the linked list possibly in reverse order */
        newEntry->next = dsthead->displayName;
        dsthead->displayName = newEntry;
    }

    /* Copy the description in several languages */
    for(UA_LocalizedTextListEntry *lt = srchead->description; lt != NULL; lt = lt->next) {
        UA_LocalizedTextListEntry *newEntry = (UA_LocalizedTextListEntry *)
            UA_calloc(1, sizeof(UA_LocalizedTextListEntry));
        if(!newEntry) {
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
            break;
        }
        retval |= UA_LocalizedText_copy(&lt->localizedText, &newEntry->localizedText);

        /* Add to the linked list possibly in reverse order */
        newEntry->next = dsthead->description;
        dsthead->description= newEntry;
    }

    dsthead->writeMask = srchead->writeMask;
    dsthead->context = srchead->context;
    dsthead->constructed = srchead->constructed;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    dsthead->monitoredItems = srchead->monitoredItems;
#endif
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Node_clear(dst);
        return retval;
    }

    /* Copy the references */
    dsthead->references = NULL;
    dsthead->referencesSize = 0;
    if(srchead->referencesSize > 0) {
        dsthead->references = (UA_NodeReferenceKind*)
            UA_calloc(srchead->referencesSize, sizeof(UA_NodeReferenceKind));
        if(!dsthead->references) {
            UA_Node_clear(dst);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        dsthead->referencesSize = srchead->referencesSize;

        for(size_t i = 0; i < srchead->referencesSize; ++i) {
            UA_NodeReferenceKind *srefs = &srchead->references[i];
            UA_NodeReferenceKind *drefs = &dsthead->references[i];
            drefs->referenceTypeIndex = srefs->referenceTypeIndex;
            drefs->isInverse = srefs->isInverse;
            drefs->hasRefTree = srefs->hasRefTree; /* initially empty */

            /* Copy all the targets */
            if(!srefs->hasRefTree) {
                drefs->targets.array = (UA_ReferenceTarget*)
                    UA_malloc(sizeof(UA_ReferenceTarget) * srefs->targetsSize);
                if(!drefs->targets.array) {
                    UA_Node_clear(dst);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                for(size_t j = 0; j < srefs->targetsSize; j++) {
                    drefs->targets.array[j].targetNameHash =
                        srefs->targets.array[j].targetNameHash;
                    retval = UA_NodePointer_copy(srefs->targets.array[j].targetId,
                                                 &drefs->targets.array[j].targetId);
                    drefs->targetsSize++; /* avoid that targetsSize == 0 in error case */
                    if(retval != UA_STATUSCODE_GOOD) {
                        UA_Node_clear(dst);
                        return retval;
                    }
                }
            } else {
                void *res = ZIP_ITER(UA_ReferenceIdTree,
                                     (UA_ReferenceIdTree*)&srefs->targets.tree.idRoot,
                                     copyTarget, drefs);
                if(res != NULL) {
                    UA_Node_clear(dst);
                    return (UA_StatusCode)(uintptr_t)res;
                }
            }

            UA_assert(srefs->targetsSize > 0);
            UA_assert(srefs->targetsSize == drefs->targetsSize);
        }
    }

    /* Copy unique content of the nodeclass */
    switch(src->head.nodeClass) {
    case UA_NODECLASS_OBJECT:
        retval = UA_ObjectNode_copy(&src->objectNode, &dst->objectNode);
        break;
    case UA_NODECLASS_VARIABLE:
        retval = UA_VariableNode_copy(&src->variableNode, &dst->variableNode);
        break;
    case UA_NODECLASS_METHOD:
        retval = UA_MethodNode_copy(&src->methodNode, &dst->methodNode);
        break;
    case UA_NODECLASS_OBJECTTYPE:
        retval = UA_ObjectTypeNode_copy(&src->objectTypeNode, &dst->objectTypeNode);
        break;
    case UA_NODECLASS_VARIABLETYPE:
        retval = UA_VariableTypeNode_copy(&src->variableTypeNode, &dst->variableTypeNode);
        break;
    case UA_NODECLASS_REFERENCETYPE:
        retval = UA_ReferenceTypeNode_copy(&src->referenceTypeNode, &dst->referenceTypeNode);
        break;
    case UA_NODECLASS_DATATYPE:
        retval = UA_DataTypeNode_copy(&src->dataTypeNode, &dst->dataTypeNode);
        break;
    case UA_NODECLASS_VIEW:
        retval = UA_ViewNode_copy(&src->viewNode, &dst->viewNode);
        break;
    default:
        break;
    }

    if(retval != UA_STATUSCODE_GOOD)
        UA_Node_clear(dst);

    return retval;
}

UA_Node *
UA_Node_copy_alloc(const UA_Node *src) {
    size_t nodesize = 0;
    switch(src->head.nodeClass) {
        case UA_NODECLASS_OBJECT:
            nodesize = sizeof(UA_ObjectNode);
            break;
        case UA_NODECLASS_VARIABLE:
            nodesize = sizeof(UA_VariableNode);
            break;
        case UA_NODECLASS_METHOD:
            nodesize = sizeof(UA_MethodNode);
            break;
        case UA_NODECLASS_OBJECTTYPE:
            nodesize = sizeof(UA_ObjectTypeNode);
            break;
        case UA_NODECLASS_VARIABLETYPE:
            nodesize = sizeof(UA_VariableTypeNode);
            break;
        case UA_NODECLASS_REFERENCETYPE:
            nodesize = sizeof(UA_ReferenceTypeNode);
            break;
        case UA_NODECLASS_DATATYPE:
            nodesize = sizeof(UA_DataTypeNode);
            break;
        case UA_NODECLASS_VIEW:
            nodesize = sizeof(UA_ViewNode);
            break;
        default:
            return NULL;
    }

    UA_Node *dst = (UA_Node*)UA_calloc(1, nodesize);
    if(!dst)
        return NULL;

    dst->head.nodeClass = src->head.nodeClass;

    UA_StatusCode retval = UA_Node_copy(src, dst);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(dst);
        return NULL;
    }
    return dst;
}
/******************************/
/* Copy Attributes into Nodes */
/******************************/

static UA_StatusCode
copyStandardAttributes(UA_Node *node, const UA_NodeAttributes *attr) {
    /* UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); */
    /* UA_QualifiedName_copy(&item->browseName, &node->browseName); */

    node->head.writeMask = attr->writeMask;
    UA_StatusCode retval = UA_Node_insertOrUpdateDescription(node, &attr->description);
    /* The new nodeset format has optional display names:
     * https://github.com/open62541/open62541/issues/2627. If the display name
     * is NULL, take the name part of the browse name */
    if(attr->displayName.text.length == 0) {
        UA_LocalizedText lt;
        UA_LocalizedText_init(&lt);
        lt.text = node->head.browseName.name;
        retval |= UA_Node_insertOrUpdateDisplayName(node, &lt);
    } else
        retval |= UA_Node_insertOrUpdateDisplayName(node, &attr->displayName);
    return retval;
}

static UA_StatusCode
copyCommonVariableAttributes(UA_VariableNode *node,
                             const UA_VariableAttributes *attr) {
    /* Copy the array dimensions */
    UA_StatusCode retval =
        UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
                      (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    node->arrayDimensionsSize = attr->arrayDimensionsSize;

    /* Data type and value rank */
    retval = UA_NodeId_copy(&attr->dataType, &node->dataType);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    node->valueRank = attr->valueRank;

    /* Copy the value */
    node->valueSourceType = UA_VALUESOURCETYPE_INTERNAL;
    retval = UA_Variant_copy(&attr->value, &node->valueSource.internal.value.value);
    node->valueSource.internal.value.hasValue =
        (node->valueSource.internal.value.value.type != NULL);

    return retval;
}

static UA_StatusCode
copyVariableNodeAttributes(UA_VariableNode *vnode,
                           const UA_VariableAttributes *attr) {
    vnode->accessLevel = attr->accessLevel;
    vnode->historizing = attr->historizing;
    vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
    return copyCommonVariableAttributes(vnode, attr);
}

static UA_StatusCode
copyVariableTypeNodeAttributes(UA_VariableTypeNode *vtnode,
                               const UA_VariableTypeAttributes *attr) {
    vtnode->isAbstract = attr->isAbstract;
    return copyCommonVariableAttributes((UA_VariableNode*)vtnode,
                                        (const UA_VariableAttributes*)attr);
}

static UA_StatusCode
copyObjectNodeAttributes(UA_ObjectNode *onode, const UA_ObjectAttributes *attr) {
    onode->eventNotifier = attr->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyReferenceTypeNodeAttributes(UA_ReferenceTypeNode *rtnode,
                                const UA_ReferenceTypeAttributes *attr) {
    rtnode->isAbstract = attr->isAbstract;
    rtnode->symmetric = attr->symmetric;
    return UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
}

static UA_StatusCode
copyObjectTypeNodeAttributes(UA_ObjectTypeNode *otnode,
                             const UA_ObjectTypeAttributes *attr) {
    otnode->isAbstract = attr->isAbstract;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyViewNodeAttributes(UA_ViewNode *vnode, const UA_ViewAttributes *attr) {
    vnode->containsNoLoops = attr->containsNoLoops;
    vnode->eventNotifier = attr->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyDataTypeNodeAttributes(UA_DataTypeNode *dtnode,
                           const UA_DataTypeAttributes *attr) {
    dtnode->isAbstract = attr->isAbstract;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyMethodNodeAttributes(UA_MethodNode *mnode,
                         const UA_MethodAttributes *attr) {
    mnode->executable = attr->executable;
    return UA_STATUSCODE_GOOD;
}

#define CHECK_ATTRIBUTES(TYPE) do {                     \
    if(attributeType != &UA_TYPES[UA_TYPES_##TYPE])     \
        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;  \
} while(0)

UA_StatusCode
UA_Node_setAttributes(UA_Node *node, const void *attributes,
                      const UA_DataType *attributeType) {
    /* Copy the attributes into the node */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(node->head.nodeClass) {
    case UA_NODECLASS_OBJECT:
        CHECK_ATTRIBUTES(OBJECTATTRIBUTES);
        retval = copyObjectNodeAttributes(&node->objectNode,
                                          (const UA_ObjectAttributes*)attributes);
        break;
    case UA_NODECLASS_VARIABLE:
        CHECK_ATTRIBUTES(VARIABLEATTRIBUTES);
        retval = copyVariableNodeAttributes(&node->variableNode,
                                            (const UA_VariableAttributes*)attributes);
        break;
    case UA_NODECLASS_OBJECTTYPE:
        CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES);
        retval = copyObjectTypeNodeAttributes(&node->objectTypeNode,
                                              (const UA_ObjectTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_VARIABLETYPE:
        CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES);
        retval = copyVariableTypeNodeAttributes(&node->variableTypeNode,
                                                (const UA_VariableTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_REFERENCETYPE:
        CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES);
        retval = copyReferenceTypeNodeAttributes(&node->referenceTypeNode,
                                                 (const UA_ReferenceTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_DATATYPE:
        CHECK_ATTRIBUTES(DATATYPEATTRIBUTES);
        retval = copyDataTypeNodeAttributes(&node->dataTypeNode,
                                            (const UA_DataTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_VIEW:
        CHECK_ATTRIBUTES(VIEWATTRIBUTES);
        retval = copyViewNodeAttributes(&node->viewNode, (const UA_ViewAttributes*)attributes);
        break;
    case UA_NODECLASS_METHOD:
        CHECK_ATTRIBUTES(METHODATTRIBUTES);
        retval = copyMethodNodeAttributes(&node->methodNode, (const UA_MethodAttributes*)attributes);
        break;
    case UA_NODECLASS_UNSPECIFIED:
    default:
        retval = UA_STATUSCODE_BADNODECLASSINVALID;
    }

    /* No need (and no promise) to call UA_Node_clear in the error case.
     * Gets caught and handled outside. */
    if(UA_LIKELY(retval == UA_STATUSCODE_GOOD))
        retval = copyStandardAttributes(node, (const UA_NodeAttributes*)attributes);
    return retval;
}

/*********************/
/* Manage References */
/*********************/

static UA_StatusCode
addReferenceTargetToTree(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
                         UA_UInt32 targetIdHash, UA_UInt32 targetNameHash) {
    UA_ReferenceTargetTreeElem *entry = (UA_ReferenceTargetTreeElem*)
        UA_malloc(sizeof(UA_ReferenceTargetTreeElem));
    if(!entry)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode res = UA_NodePointer_copy(targetId, &entry->target.targetId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(entry);
        return res;
    }

    entry->targetIdHash = targetIdHash;
    entry->target.targetNameHash = targetNameHash;

    ZIP_INSERT(UA_ReferenceIdTree,
               (UA_ReferenceIdTree*)&rk->targets.tree.idRoot, entry);
    ZIP_INSERT(UA_ReferenceNameTree,
               (UA_ReferenceNameTree*)&rk->targets.tree.nameRoot, entry);

    rk->targetsSize++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addReferenceTarget(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
                   UA_UInt32 targetNameHash) {
    /* Insert into tree */
    if(rk->hasRefTree) {
        UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(targetId);
        return addReferenceTargetToTree(rk, targetId, UA_ExpandedNodeId_hash(&en),
                                        targetNameHash);
    }

    /* Insert to the array */
    UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*)
        UA_realloc(rk->targets.array,
                   sizeof(UA_ReferenceTarget) * (rk->targetsSize + 1));
    if(!newRefs)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rk->targets.array = newRefs;

    UA_StatusCode retval =
        UA_NodePointer_copy(targetId,
                            &rk->targets.array[rk->targetsSize].targetId);
    rk->targets.array[rk->targetsSize].targetNameHash = targetNameHash;
    if(retval != UA_STATUSCODE_GOOD) {
        if(rk->targetsSize == 0) {
            UA_free(rk->targets.array);
            rk->targets.array = NULL;
        }
        return retval;
    }

    rk->targetsSize++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addReferenceKind(UA_NodeHead *head, UA_Byte refTypeIndex, UA_Boolean isForward,
                 const UA_NodePointer target, UA_UInt32 targetBrowseNameHash) {
    UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*)
        UA_realloc(head->references,
                   sizeof(UA_NodeReferenceKind) * (head->referencesSize+1));
    if(!refs)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    head->references = refs;

    UA_NodeReferenceKind *newRef = &refs[head->referencesSize];
    memset(newRef, 0, sizeof(UA_NodeReferenceKind));
    newRef->referenceTypeIndex = refTypeIndex;
    newRef->isInverse = !isForward;
    UA_StatusCode res = addReferenceTarget(newRef, target, targetBrowseNameHash);
    if(res != UA_STATUSCODE_GOOD) {
        if(head->referencesSize == 0) {
            UA_free(head->references);
            head->references = NULL;
        }
        return res;
    }

    head->referencesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
                     const UA_ExpandedNodeId *targetNodeId,
                     UA_UInt32 targetBrowseNameHash) {
    /* Find the matching reference kind */
    for(size_t i = 0; i < node->head.referencesSize; ++i) {
        UA_NodeReferenceKind *refs = &node->head.references[i];

        /* Reference direction does not match */
        if(refs->isInverse == isForward)
            continue;

        /* Reference type does not match */
        if(refs->referenceTypeIndex != refTypeIndex)
            continue;

        /* Does an identical reference already exist? */
        const UA_ReferenceTarget *found =
            UA_NodeReferenceKind_findTarget(refs, targetNodeId);
        if(found)
            return UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED;

        /* If there are many references, attempt to switch to the
         * tree-representation. This speeds up all reference lookups. Continue
         * with the array-representation in case of an error. */
        if(!refs->hasRefTree && refs->targetsSize >= 31)
            UA_NodeReferenceKind_switch(refs);

        /* Add to existing ReferenceKind */
        return addReferenceTarget(refs, UA_NodePointer_fromExpandedNodeId(targetNodeId),
                                  targetBrowseNameHash);
    }

    /* Add new ReferenceKind for the target */
    return addReferenceKind(&node->head, refTypeIndex, isForward,
                            UA_NodePointer_fromExpandedNodeId(targetNodeId),
                            targetBrowseNameHash);

}

UA_StatusCode
UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
                        const UA_ExpandedNodeId *targetNodeId) {
    UA_NodeHead *head = &node->head;
    for(size_t i = 0; i < head->referencesSize; i++) {
        UA_NodeReferenceKind *refs = &head->references[i];
        if(isForward == refs->isInverse)
            continue;
        if(refTypeIndex != refs->referenceTypeIndex)
            continue;

        /* Cast out the const qualifier (hack!) */
        UA_ReferenceTarget *target = (UA_ReferenceTarget*)(uintptr_t)
            UA_NodeReferenceKind_findTarget(refs, targetNodeId);
        if(!target)
            continue;

        /* Ok, delete the reference. Cannot fail */
        refs->targetsSize--;

        if(!refs->hasRefTree) {
            /* Remove from array */
            UA_NodePointer_clear(&target->targetId);

            /* Elements remaining. Realloc. */
            if(refs->targetsSize > 0) {
                if(target != &refs->targets.array[refs->targetsSize])
                    *target = refs->targets.array[refs->targetsSize];
                UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*)
                    UA_realloc(refs->targets.array,
                               sizeof(UA_ReferenceTarget) * refs->targetsSize);
                if(newRefs)
                    refs->targets.array = newRefs;
                return UA_STATUSCODE_GOOD; /* Realloc allowed to fail */
            }

            /* Remove the last target. Remove the ReferenceKind below */
            UA_free(refs->targets.array);
        } else {
            UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*)target;
            ZIP_REMOVE(UA_ReferenceIdTree,
                       (UA_ReferenceIdTree*)&refs->targets.tree.idRoot, elem);
            ZIP_REMOVE(UA_ReferenceNameTree,
                       (UA_ReferenceNameTree*)&refs->targets.tree.nameRoot, elem);
            UA_NodePointer_clear(&target->targetId);
            UA_free(target);
            if(refs->targetsSize > 0)
                return UA_STATUSCODE_GOOD;
        }

        /* No targets remaining. Remove the ReferenceKind. */
        head->referencesSize--;
        if(head->referencesSize > 0) {
            /* No target for the ReferenceType remaining. Remove and shrink down
             * allocated buffer. Ignore errors in case memory buffer could not
             * be shrinked down. */
            if(i != head->referencesSize)
                head->references[i] = head->references[node->head.referencesSize];
            UA_NodeReferenceKind *newRefs = (UA_NodeReferenceKind*)
                UA_realloc(head->references,
                           sizeof(UA_NodeReferenceKind) * head->referencesSize);
            if(newRefs)
                head->references = newRefs;
        } else {
            /* No remaining references of any ReferenceType */
            UA_free(head->references);
            head->references = NULL;
        }
        return UA_STATUSCODE_GOOD;
    }
    return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
}

void
UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet) {
    UA_NodeHead *head = &node->head;
    UA_assert(head->references != NULL || head->referencesSize == 0);
    size_t i = 0;
    while(i < head->referencesSize) {
        /* Keep the references of this type? */
        UA_NodeReferenceKind *refs = &head->references[i];
        if(UA_ReferenceTypeSet_contains(keepSet, refs->referenceTypeIndex)){
            i++;
            continue;
        }

        /* Remove all target entries. Don't remove entries from browseName tree.
         * The entire ReferenceKind will be removed anyway. */
        if(!refs->hasRefTree) {
            for(size_t j = 0; j < refs->targetsSize; j++) {
                /* Consistency requirement: If refs->targetsSize > 0, then the
                 * targets array is non-NULL */
                UA_assert(refs->targets.array != NULL);
                UA_NodePointer_clear(&refs->targets.array[j].targetId);
            }
            UA_free(refs->targets.array);
        } else {
            ZIP_ITER(UA_ReferenceIdTree,
                     (UA_ReferenceIdTree*)&refs->targets.tree.idRoot,
                     removeTreeEntry, NULL);
        }

        /* Move last references-kind entry to this position. Don't memcpy over
         * the same position. Don't increment i: the swapped-in element must be
         * checked on the next iteration. */
        head->referencesSize--;
        if(i != head->referencesSize)
            head->references[i] = head->references[head->referencesSize];
    }

    if(head->referencesSize > 0) {
        /* Realloc to save memory. Ignore if realloc fails. */
        UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*)
            UA_realloc(head->references,
                       sizeof(UA_NodeReferenceKind) * head->referencesSize);
        if(refs)
            head->references = refs;
    } else {
        /* The array is empty. Remove. */
        UA_free(head->references);
        head->references = NULL;
    }
}

void UA_Node_deleteReferences(UA_Node *node) {
    UA_ReferenceTypeSet noRefs;
    UA_ReferenceTypeSet_init(&noRefs);
    UA_Node_deleteReferencesSubset(node, &noRefs);
}

static UA_StatusCode
UA_Node_insertOrUpdateLocale(UA_LocalizedTextListEntry **root,
                             const UA_LocalizedText *value) {
    UA_StatusCode res;
    UA_LocalizedTextListEntry *lt, *prev = NULL;
    for(lt = *root; lt != NULL; prev = lt, lt = lt->next) {
        if(!UA_String_equal(&value->locale, &lt->localizedText.locale))
            continue;

        /* No text -> remove the entry for this locale */
        if(value->text.length == 0) {
            if(prev == NULL)
                *root = lt->next;
            else
                prev->next = lt->next;
            UA_LocalizedText_clear(&lt->localizedText);
            UA_free(lt);
            return UA_STATUSCODE_GOOD;
        }

        /* First make a copy of the text, if this succeeds replace the old
         * version */
        UA_String tmp;
        res = UA_String_copy(&value->text, &tmp);
        if(res != UA_STATUSCODE_GOOD)
            return res;

        UA_String_clear(&lt->localizedText.text);
        lt->localizedText.text = tmp;
        return UA_STATUSCODE_GOOD;
    }

    /* The locale does not exist so far */

    /* Do nothing if a non-existing locale should be removed */
    if(value->text.length == 0)
        return UA_STATUSCODE_GOOD;

    /* Add a new localized text */
    lt = (UA_LocalizedTextListEntry *)UA_malloc(sizeof(UA_LocalizedTextListEntry));
    if(!lt)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    res = UA_LocalizedText_copy(value, &lt->localizedText);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(lt);
        return res;
    }

    lt->next = *root;
    *root = lt;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Node_insertOrUpdateDisplayName(UA_Node *node,
                                  const UA_LocalizedText *displayName) {
    return UA_Node_insertOrUpdateLocale(&node->head.displayName, displayName);
}

UA_StatusCode
UA_Node_insertOrUpdateDescription(UA_Node *node,
                                  const UA_LocalizedText *description) {
    return UA_Node_insertOrUpdateLocale(&node->head.description, description);
}

/**** amalgamated original file "/src/server/ua_server.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Julian Grothoff
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 *    Copyright 2022-2025 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS
#endif

#ifdef UA_ENABLE_NODESET_INJECTOR
#endif

#ifdef UA_ENABLE_ENCRYPTION
#endif

#define STARTCHANNELID 1
#define STARTTOKENID 1

/**********************/
/* Namespace Handling */
/**********************/

/* The NS1 Uri can be changed by the user to some custom string. This method is
 * called to initialize the NS1 Uri if it is not set before to the default
 * Application URI.
 *
 * This is done as soon as the Namespace Array is read or written via node value
 * read / write services, or UA_Server_addNamespace, or UA_Server_getNamespaceByIndex
 * UA_Server_getNamespaceByName or UA_Server_run_startup is called.
 *
 * Therefore one has to set the custom NS1 URI before one of the previously
 * mentioned steps. */

void
setupNs1Uri(UA_Server *server) {
    if(!server->namespaces[1].data) {
        UA_String_copy(&server->config.applicationDescription.applicationUri,
                       &server->namespaces[1]);
    }
}

UA_UInt16 addNamespace(UA_Server *server, const UA_String name) {
    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);

    /* Check if the namespace already exists in the server's namespace array */
    for(size_t i = 0; i < server->namespacesSize; ++i) {
        if(UA_String_equal(&name, &server->namespaces[i]))
            return (UA_UInt16) i;
    }

    /* Make the array bigger */
    UA_String *newNS = (UA_String*)UA_realloc(server->namespaces,
                                              sizeof(UA_String) * (server->namespacesSize + 1));
    UA_CHECK_MEM(newNS, return 0);

    server->namespaces = newNS;

    /* Copy the namespace string */
    UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]);
    UA_CHECK_STATUS(retval, return 0);

    /* Announce the change (otherwise, the array appears unchanged) */
    ++server->namespacesSize;
    return (UA_UInt16)(server->namespacesSize - 1);
}

UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
    /* Override const attribute to get string (dirty hack) */
    UA_String nameString;
    nameString.length = strlen(name);
    nameString.data = (UA_Byte*)(uintptr_t)name;
    lockServer(server);
    UA_UInt16 retVal = addNamespace(server, nameString);
    unlockServer(server);
    return retVal;
}

UA_ServerConfig*
UA_Server_getConfig(UA_Server *server) {
    UA_CHECK_MEM(server, return NULL);
    return &server->config;
}

UA_StatusCode
getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
                   size_t *foundIndex) {
    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    for(size_t idx = 0; idx < server->namespacesSize; idx++) {
        if(UA_String_equal(&server->namespaces[idx], &namespaceUri)) {
            (*foundIndex) = idx;
            res = UA_STATUSCODE_GOOD;
            break;
        }
    }
    return res;
}

UA_StatusCode
getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
                   UA_String *foundUri) {
    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(namespaceIndex >= server->namespacesSize)
        return res;
    res = UA_String_copy(&server->namespaces[namespaceIndex], foundUri);
    return res;
}

UA_StatusCode
UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
                             size_t *foundIndex) {
    lockServer(server);
    UA_StatusCode res = getNamespaceByName(server, namespaceUri, foundIndex);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
                              UA_String *foundUri) {
    lockServer(server);
    UA_StatusCode res = getNamespaceByIndex(server, namespaceIndex, foundUri);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
                               UA_NodeIteratorCallback callback, void *handle) {
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = parentNodeId;
    bd.browseDirection = UA_BROWSEDIRECTION_BOTH;
    bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_ISFORWARD;

    UA_BrowseResult br = UA_Server_browse(server, 0, &bd);
    UA_StatusCode res = br.statusCode;
    UA_CHECK_STATUS(res, goto cleanup);

    for(size_t i = 0; i < br.referencesSize; i++) {
        if(!UA_ExpandedNodeId_isLocal(&br.references[i].nodeId))
            continue;
        res = callback(br.references[i].nodeId.nodeId, !br.references[i].isForward,
                       br.references[i].referenceTypeId, handle);
        UA_CHECK_STATUS(res, goto cleanup);
    }
cleanup:
    UA_BrowseResult_clear(&br);
    return res;
}

/********************/
/* GDS Transaction  */
/********************/

UA_StatusCode
UA_GDSTransaction_init(UA_GDSTransaction *transaction, UA_Server *server, const UA_NodeId sessionId) {
    if(!transaction || !server)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString csr = UA_BYTESTRING_NULL;
    if(transaction->localCsrCertificate.length > 0)
        csr = transaction->localCsrCertificate;

    memset(transaction, 0, sizeof(UA_GDSTransaction));

    transaction->state = UA_GDSTRANSACTIONSTATE_PENDING;
    UA_NodeId_copy(&sessionId, &transaction->sessionId);
    transaction->server = server;
    transaction->localCsrCertificate = csr;

    return UA_STATUSCODE_GOOD;
}

UA_CertificateGroup*
UA_GDSTransaction_getCertificateGroup(UA_GDSTransaction *transaction,
                                      const UA_CertificateGroup *certGroup) {
#ifdef UA_ENABLE_ENCRYPTION
    if(!transaction || !certGroup)
        return NULL;

    /* Check if transaction was initialized */
    if(transaction->state != UA_GDSTRANSACTIONSTATE_PENDING)
        return NULL;

    for(size_t i = 0; i < transaction->certGroupSize; i++) {
        UA_CertificateGroup *group = &transaction->certGroups[i];
        if(UA_NodeId_equal(&group->certificateGroupId, &certGroup->certificateGroupId))
            return group;
    }

    /* If the certGroup does not exist, create a new one */
    transaction->certGroups = (UA_CertificateGroup*)UA_realloc(transaction->certGroups, (transaction->certGroupSize + 1) * sizeof(UA_CertificateGroup));
    if(!transaction->certGroups)
        return NULL;

    transaction->certGroupSize++;

    memset(&transaction->certGroups[transaction->certGroupSize-1], 0, sizeof(UA_CertificateGroup));

    UA_TrustListDataType trustList;
    UA_TrustListDataType_init(&trustList);
    trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;
    certGroup->getTrustList((UA_CertificateGroup*)(uintptr_t)certGroup, &trustList);

    /* Set up the parameters */
    static UA_THREAD_LOCAL UA_KeyValuePair params[1] = {
        {{0, UA_STRING_STATIC("max-trust-listsize")}, {0}}
    };
    UA_KeyValueMap paramsMap = {1, params};

    UA_ServerConfig *config = UA_Server_getConfig(transaction->server);
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize,
                         &UA_TYPES[UA_TYPES_UINT32]);

    UA_CertificateGroup_Memorystore(&transaction->certGroups[transaction->certGroupSize-1],
        (UA_NodeId*)(uintptr_t)&certGroup->certificateGroupId, &trustList, certGroup->logging, &paramsMap);

    UA_TrustListDataType_clear(&trustList);

    return &transaction->certGroups[transaction->certGroupSize-1];
#else
    return NULL;
#endif
}

UA_StatusCode
UA_GDSTransaction_addCertificateInfo(UA_GDSTransaction *transaction,
                                     const UA_NodeId certificateGroupId,
                                     const UA_NodeId certificateTypeId,
                                     const UA_ByteString *certificate,
                                     const UA_ByteString *privateKey) {
    if(!transaction || !certificate)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Check if transaction was initialized */
    if(transaction->state != UA_GDSTRANSACTIONSTATE_PENDING)
        return UA_STATUSCODE_BADINVALIDSTATE;

    /* Check if an entry with certificateGroupId and certificateTypeId already exists */
    for(size_t i = 0; i < transaction->certificateInfosSize; i++) {
        UA_GDSCertificateInfo *certInfo = &transaction->certificateInfos[i];

        if(!UA_NodeId_equal(&certInfo->certificateGroup, &certificateGroupId) ||
           !UA_NodeId_equal(&certInfo->certificateType, &certificateTypeId))
            continue;

        UA_ByteString_clear(&certInfo->certificate);
        UA_ByteString_clear(&certInfo->privateKey);

        UA_ByteString_copy(certificate, &certInfo->certificate);
        certInfo->privateKey = UA_BYTESTRING_NULL;
        if(privateKey)
            UA_ByteString_copy(privateKey, &certInfo->privateKey);

        return UA_STATUSCODE_GOOD;
    }

    UA_GDSCertificateInfo *newCertInfos = (UA_GDSCertificateInfo *)UA_realloc(transaction->certificateInfos,
        (transaction->certificateInfosSize + 1) * sizeof(UA_GDSCertificateInfo));
    if(!newCertInfos)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    transaction->certificateInfos = newCertInfos;

    UA_GDSCertificateInfo *newCertInfo = &transaction->certificateInfos[transaction->certificateInfosSize];
    UA_ByteString_copy(certificate, &newCertInfo->certificate);
    UA_NodeId_copy(&certificateGroupId, &newCertInfo->certificateGroup);
    UA_NodeId_copy(&certificateTypeId, &newCertInfo->certificateType);
    newCertInfo->privateKey = UA_BYTESTRING_NULL;
    if(privateKey)
        UA_ByteString_copy(privateKey, &newCertInfo->privateKey);

    transaction->certificateInfosSize++;

    return UA_STATUSCODE_GOOD;
}

void UA_GDSTransaction_clear(UA_GDSTransaction *transaction) {
    if(!transaction)
        return;

    transaction->state = UA_GDSTRANSACTIONSTATE_FRESH;
    transaction->server = NULL;
    UA_NodeId_clear(&transaction->sessionId);
    UA_ByteString_clear(&transaction->localCsrCertificate);

    if(transaction->certGroups) {
        for(size_t i = 0; i < transaction->certGroupSize; i++) {
            transaction->certGroups[i].clear(&transaction->certGroups[i]);
        }
        UA_free(transaction->certGroups);
        transaction->certGroupSize = 0;
        transaction->certGroups = NULL;
    }

    if(transaction->certificateInfos) {
        for(size_t i = 0; i < transaction->certificateInfosSize; i++) {
            UA_ByteString_clear(&transaction->certificateInfos[i].certificate);
            UA_ByteString_clear(&transaction->certificateInfos[i].privateKey);
            UA_NodeId_clear(&transaction->certificateInfos[i].certificateGroup);
            UA_NodeId_clear(&transaction->certificateInfos[i].certificateType);
        }
        UA_free(transaction->certificateInfos);
        transaction->certificateInfosSize = 0;
        transaction->certificateInfos = NULL;
    }
}

void UA_GDSTransaction_delete(UA_GDSTransaction *transaction) {
    UA_GDSTransaction_clear(transaction);
    UA_free(transaction);
}

#ifndef UA_ENABLE_GDS_PUSHMANAGEMENT
/* Minimal stub: when GDS push management is not compiled in,
 * only the embedded transaction needs to be cleared. */
void
UA_GDSManager_clear(UA_GDSManager *gdsManager) {
    if(!gdsManager)
        return;
    gdsManager->checkSessionCallbackId = 0;
    UA_GDSTransaction_clear(&gdsManager->transaction);
}
#endif

/*********************/
/* Server Components */
/*********************/

enum ZIP_CMP
cmpServerComponent(const UA_UInt64 *a, const UA_UInt64 *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

void
addServerComponent(UA_Server *server, UA_ServerComponent *sc,
                   UA_UInt64 *identifier) {
    if(!sc)
        return;

    sc->identifier = ++server->serverComponentIds;
    ZIP_INSERT(UA_ServerComponentTree, &server->serverComponents, sc);

    /* Start the component if the server is started */
    if(server->state == UA_LIFECYCLESTATE_STARTED && sc->start)
        sc->start(sc, server);

    if(identifier)
        *identifier = sc->identifier;
}

static void *
findServerComponent(void *context, UA_ServerComponent *sc) {
    UA_String *name = (UA_String*)context;
    return (UA_String_equal(&sc->name, name)) ? sc : NULL;
}

UA_ServerComponent *
getServerComponentByName(UA_Server *server, UA_String name) {
    return (UA_ServerComponent*)
        ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
                 findServerComponent, &name);
}

static void *
startServerComponent(void *server, UA_ServerComponent *sc) {
    sc->start(sc, (UA_Server*)server);
    return NULL;
}

static void *
stopServerComponent(void *_, UA_ServerComponent *sc) {
    sc->stop(sc);
    return NULL;
}

/* ZIP_ITER returns NULL only if all components are stopped */
static void *
checkServerComponent(void *_, UA_ServerComponent *sc) {
    return (sc->state == UA_LIFECYCLESTATE_STOPPED) ? NULL : (void*)0x01;
}

/********************/
/* Server Lifecycle */
/********************/

/* The server needs to be stopped before it can be deleted */
UA_StatusCode
UA_Server_delete(UA_Server *server) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(server->state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "The server must be fully stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    lockServer(server);

    session_list_entry *current, *temp;
    LIST_FOREACH_SAFE(current, &server->sessions, pointers, temp) {
        UA_Session_remove(server, &current->session, UA_SHUTDOWNREASON_CLOSE);
    }
    UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Remove subscriptions without a session */
    UA_Subscription *sub, *sub_tmp;
    LIST_FOREACH_SAFE(sub, &server->subscriptions, serverListEntry, sub_tmp) {
        UA_Subscription_delete(server, sub);
    }

#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
    UA_ConditionList_delete(server);
#endif

#endif

#if UA_MULTITHREADING >= 100
    UA_AsyncManager_clear(&server->asyncManager, server);
#endif

    /* Clean up the Admin Session */
    UA_Session_clear(&server->adminSession, server);
#ifdef UA_ENABLE_SUBSCRIPTIONS
    server->adminSubscription = NULL;
    UA_assert(server->monitoredItemsSize == 0);
    UA_assert(server->subscriptionsSize == 0);
#endif

    /* Remove all server components (all stopped by now) */
    UA_ServerComponent *top;
    while((top = ZIP_ROOT(&server->serverComponents))) {
        UA_assert(top->state == UA_LIFECYCLESTATE_STOPPED);
        top->clear(top);
        ZIP_REMOVE(UA_ServerComponentTree, &server->serverComponents, top);
        UA_free(top);
    }

    unlockServer(server); /* The timer has its own mutex */

    /* Clean up the config */
    UA_ServerConfig_clear(&server->config);

#if UA_MULTITHREADING >= 100
    UA_LOCK_DESTROY(&server->serviceMutex);
#endif

    UA_GDSManager_clear(&server->gdsManager);

    /* Clean up the custom datatypes */
    if(server->customTypes_internal != NULL) {
        for(size_t i = 0; i < server->customTypes_internalSize; i++) {
            UA_DataTypeArray *curr = &server->customTypes_internal[i];
            for(size_t j = 0; j < curr->typesSize; j++)
                UA_DataType_clear(&curr->types[j]);
            UA_free(curr->types);
        }
        UA_free(server->customTypes_internal);
    }

    /* Delete the server itself and return */
    UA_free(server);
    return UA_STATUSCODE_GOOD;
}

/* Regular house-keeping tasks. Removing unused and timed-out channels and
 * sessions. */
static void
serverHouseKeeping(UA_Server *server, void *_) {
    lockServer(server);
    UA_EventLoop *el = server->config.eventLoop;
    cleanupSessions(server, el->dateTime_nowMonotonic(el));
    unlockServer(server);
}

/********************/
/* Server Lifecycle */
/********************/

static
UA_INLINE
UA_Boolean UA_Server_NodestoreIsConfigured(UA_Server *server) {
    return (server->config.nodestore && server->config.nodestore->getNode);
}

static UA_Server *
UA_Server_init(UA_Server *server) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_CHECK_FATAL(UA_Server_NodestoreIsConfigured(server), goto cleanup,
                   server->config.logging, UA_LOGCATEGORY_SERVER,
                   "No Nodestore configured in the server");

    /* Init start time to zero, the actual start time will be sampled in
     * UA_Server_run_startup() */
    server->startTime = 0;

    /* Set a seed for non-cyptographic randomness */
#ifndef UA_ENABLE_DETERMINISTIC_RNG
    UA_random_seed((UA_UInt64)UA_DateTime_now());
#endif

    UA_LOCK_INIT(&server->serviceMutex);
    lockServer(server);

    /* Initialize the adminSession */
    UA_Session_init(&server->adminSession);
    server->adminSession.sessionId.identifierType = UA_NODEIDTYPE_GUID;
    server->adminSession.sessionId.identifier.guid.data1 = 1;
    server->adminSession.validTill = UA_INT64_MAX;
    server->adminSession.sessionName = UA_STRING_ALLOC("Administrator");

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Initialize the adminSubscription */
    server->adminSubscription = UA_Subscription_new();
    UA_CHECK_MEM(server->adminSubscription, goto cleanup);
    UA_Session_attachSubscription(&server->adminSession, server->adminSubscription);
#endif

    /* Create Namespaces 0 and 1
     * Ns1 will be filled later with the uri from the app description */
    server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
    UA_CHECK_MEM(server->namespaces, goto cleanup);

    server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
    server->namespaces[1] = UA_STRING_NULL;
    server->namespacesSize = 2;

    /* Initialize Session Management */
    LIST_INIT(&server->sessions);
    server->sessionCount = 0;

    /* Initialize SecureChannel */
    TAILQ_INIT(&server->channels);
    /* TODO: use an ID that is likely to be unique after a restart */
    server->lastChannelId = STARTCHANNELID;
    server->lastTokenId = STARTTOKENID;

#if UA_MULTITHREADING >= 100
    UA_AsyncManager_init(&server->asyncManager, server);
#endif

    /* Initialize namespace 0 */
#ifdef UA_GENERATED_NAMESPACE_ZERO
    /* Standard configuration: generate NS0 nodes at runtime */
    res = initNS0(server);
#else
    /* NONE configuration: NS0 pre-loaded by external nodestore (e.g., ROM).
     * Only connect data sources for dynamic values like ServerTime, ServerStatus, etc. */
    res = initNS0_dataSources(server);
#endif
    UA_CHECK_STATUS(res, goto cleanup);

#ifdef UA_ENABLE_GDS_PUSHMANAGEMENT
    res = initNS0PushManagement(server);
    UA_CHECK_STATUS(res, goto cleanup);
#endif

#ifdef UA_ENABLE_NODESET_INJECTOR
    res = UA_Server_injectNodesets(server);
    UA_CHECK_STATUS(res, goto cleanup);
#endif

    /* Initialize the binay protocol support */
    addServerComponent(server, UA_BinaryProtocolManager_new(server), NULL);

    /* Initialized Discovery */
#ifdef UA_ENABLE_DISCOVERY
    addServerComponent(server, UA_DiscoveryManager_new(), NULL);
#endif

    /* Initialize PubSub */
#ifdef UA_ENABLE_PUBSUB
    if(server->config.pubsubEnabled)
        addServerComponent(server, UA_PubSubManager_new(server), NULL);
#endif

    /* For all custom datatypes, check if they are represented in the
     * information model. If not, add them. */
#ifdef UA_ENABLE_TYPEDESCRIPTION
    for(const UA_DataTypeArray *custom = server->config.customDataTypes;
        custom != NULL; custom = custom->next) {
        for(size_t i = 0; i < custom->typesSize; i++) {
            const UA_DataType *type = &custom->types[i];
            if(type->typeKind != UA_DATATYPEKIND_STRUCTURE &&
               type->typeKind != UA_DATATYPEKIND_OPTSTRUCT &&
               type->typeKind != UA_DATATYPEKIND_UNION)
                continue;
            const UA_Node *node =
                UA_NODESTORE_GET_SELECTIVE(server, &type->typeId, 0,
                                           UA_REFERENCETYPESET_NONE,
                                           UA_BROWSEDIRECTION_INVALID);
            if(node) {
                UA_NODESTORE_RELEASE(server, node);
                continue;
            }

            UA_QualifiedName dataTypeBrowseName =
                {type->typeId.namespaceIndex, UA_STRING_STATIC((char*)(uintptr_t)type->typeName)};
            UA_DataTypeAttributes dta = UA_DataTypeAttributes_default;
            dta.displayName.text = UA_STRING((char*)(uintptr_t)type->typeName);
            res = UA_Server_addDataTypeNode(server, type->typeId, UA_NS0ID(STRUCTURE),
                                            UA_NS0ID(HASSUBTYPE), dataTypeBrowseName,
                                            dta, NULL, NULL);
            if(res != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                               "Could not add DataTypeNode for %s (%N)",
                               type->typeName, type->typeId);
            }
        }
    }
#endif

    unlockServer(server);
    return server;

 cleanup:
    unlockServer(server);
    UA_Server_delete(server);
    return NULL;
}

UA_Server *
UA_Server_newWithConfig(UA_ServerConfig *config) {
    UA_CHECK_MEM(config, return NULL);

    UA_CHECK_LOG(config->eventLoop != NULL, return NULL, ERROR,
                 config->logging, UA_LOGCATEGORY_SERVER, "No EventLoop configured");

    UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));
    UA_CHECK_MEM(server, UA_ServerConfig_clear(config); return NULL);

    server->config = *config;

    /* If not defined, set logging to what the server has */
    if(!server->config.secureChannelPKI.logging)
        server->config.secureChannelPKI.logging = server->config.logging;
    if(!server->config.sessionPKI.logging)
        server->config.sessionPKI.logging = server->config.logging;

    /* Reset the old config */
    memset(config, 0, sizeof(UA_ServerConfig));
    return UA_Server_init(server);
}

/* Returns if the server should be shut down immediately */
static UA_Boolean
setServerShutdown(UA_Server *server) {
    if(server->endTime != 0)
        return false;
    if(server->config.shutdownDelay == 0)
        return true;

    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                   "Shutting down the server with a delay of %i ms",
                   (int)server->config.shutdownDelay);

    UA_EventLoop *el = server->config.eventLoop;
    server->endTime = el->dateTime_now(el) + (UA_DateTime)(server->config.shutdownDelay * UA_DATETIME_MSEC);

    /* Call the application notification callback */
    UA_ServerConfig *config = &server->config;
    if(config->lifecycleNotificationCallback)
        config->lifecycleNotificationCallback(server, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_SHUTDOWN,
                                              UA_KEYVALUEMAP_NULL);
    if(config->globalNotificationCallback)
        config->globalNotificationCallback(server, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_SHUTDOWN,
                                           UA_KEYVALUEMAP_NULL);

    return false;
}

/*******************/
/* Timed Callbacks */
/*******************/

UA_StatusCode
UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
                           void *data, UA_DateTime date, UA_UInt64 *callbackId) {
    lockServer(server);
    UA_EventLoop *el = server->config.eventLoop;
    UA_StatusCode retval = el->addTimer(el, (UA_Callback)callback, server, data,
                                        0.0, &date, UA_TIMERPOLICY_ONCE, callbackId);
    unlockServer(server);
    return retval;
}

UA_StatusCode
addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                    void *data, UA_Double interval_ms, UA_UInt64 *callbackId) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_EventLoop *el = server->config.eventLoop;
    return el->addTimer(el, (UA_Callback)callback, server, data, interval_ms, NULL,
                        UA_TIMERPOLICY_CURRENTTIME, callbackId);
}

UA_StatusCode
UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                              void *data, UA_Double interval_ms,
                              UA_UInt64 *callbackId) {
    lockServer(server);
    UA_StatusCode res = addRepeatedCallback(server, callback, data, interval_ms, callbackId);
    unlockServer(server);
    return res;
}

UA_StatusCode
changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                               UA_Double interval_ms) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_EventLoop *el = server->config.eventLoop;
    return el->modifyTimer(el, callbackId, interval_ms, NULL, UA_TIMERPOLICY_CURRENTTIME);
}

UA_StatusCode
UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                                         UA_Double interval_ms) {
    lockServer(server);
    UA_StatusCode retval = changeRepeatedCallbackInterval(server, callbackId, interval_ms);
    unlockServer(server);
    return retval;
}

void
removeCallback(UA_Server *server, UA_UInt64 callbackId) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_EventLoop *el = server->config.eventLoop;
    el->removeTimer(el, callbackId);
}

void
UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId) {
    lockServer(server);
    removeCallback(server, callbackId);
    unlockServer(server);
}

/* When the trustlist changes, re-check the certificates of all
 * SecureChannels */
static void
secureChannel_delayedCloseTrustList(void *application, void *context) {
    UA_DelayedCallback *dc = (UA_DelayedCallback*)context;
    UA_Server *server = (UA_Server*)application;

    UA_CertificateGroup *certGroup = &server->config.secureChannelPKI;
    UA_SecureChannel *channel;
    TAILQ_FOREACH(channel, &server->channels, serverEntry) {
        if(channel->state != UA_SECURECHANNELSTATE_CLOSED &&
           channel->state != UA_SECURECHANNELSTATE_CLOSING)
            continue;
        if(channel->remoteCertificate.length == 0)
            continue; /* SecureChannels w/o security */
        UA_StatusCode res =
            validateCertificate(server, certGroup, channel, channel->sessions,
                                "RenewTrustList", NULL, channel->remoteCertificate);
        if(res != UA_STATUSCODE_GOOD)
            UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
    }
    UA_free(dc);
}

static UA_CertificateGroup*
getCertificateGroup(UA_Server *server, const UA_NodeId certificateGroupId) {
    UA_NodeId defaultApplicationGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    UA_NodeId defaultUserTokenGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
    if(UA_NodeId_equal(&certificateGroupId, &defaultApplicationGroup)) {
        return &server->config.secureChannelPKI;
    }
    if(UA_NodeId_equal(&certificateGroupId, &defaultUserTokenGroup)) {
        return &server->config.sessionPKI;
    }
    return NULL;
}

UA_StatusCode
UA_Server_addCertificates(UA_Server *server,
                          const UA_NodeId certificateGroupId,
                          UA_ByteString *certificates,
                          size_t certificatesSize,
                          UA_ByteString *crls,
                          size_t crlsSize,
                          const UA_Boolean isTrusted,
                          const UA_Boolean appendCertificates) {
    UA_CertificateGroup *certGroup = getCertificateGroup(server, certificateGroupId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_TrustListDataType trustList;
    UA_TrustListDataType_init(&trustList);

    if(isTrusted) {
        trustList.specifiedLists = UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES | UA_TRUSTLISTMASKS_TRUSTEDCRLS;
        trustList.trustedCertificates = certificates;
        trustList.trustedCertificatesSize = certificatesSize;
        trustList.trustedCrls = crls;
        trustList.trustedCrlsSize = crlsSize;
    } else {
        trustList.specifiedLists = UA_TRUSTLISTMASKS_ISSUERCERTIFICATES | UA_TRUSTLISTMASKS_ISSUERCRLS;
        trustList.issuerCertificates = certificates;
        trustList.issuerCertificatesSize = certificatesSize;
        trustList.issuerCrls = crls;
        trustList.issuerCrlsSize = crlsSize;
    }

    /* When adding certificate files to the TrustList,
     * it is not necessary to check the trust status of the existing SecureChannels. */
    if(appendCertificates)
        return certGroup->addToTrustList(certGroup, &trustList);

    UA_StatusCode retval = certGroup->setTrustList(certGroup, &trustList);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_calloc(1, sizeof(UA_DelayedCallback));
    if(!dc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    dc->callback = secureChannel_delayedCloseTrustList;
    dc->application = server;
    dc->context = dc;

    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, dc);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_removeCertificates(UA_Server *server,
                             const UA_NodeId certificateGroupId,
                             UA_ByteString *certificates,
                             size_t certificatesSize,
                             const UA_Boolean isTrusted) {
    UA_CertificateGroup *certGroup = getCertificateGroup(server, certificateGroupId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_ByteString *crls = NULL;
    size_t crlsSize = 0;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < certificatesSize; i++) {
        retval = certGroup->getCertificateCrls(certGroup, &certificates[i], isTrusted, &crls, &crlsSize);
        /* Tolerate "Bad_NoMatch" to support removing CA certificates that do
         * not have an associated CRL. */
        if((retval != UA_STATUSCODE_GOOD) && (retval != UA_STATUSCODE_BADNOMATCH)) {
            UA_Array_delete(crls, crlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
            return retval;
        }
    }

    UA_TrustListDataType trustList;
    UA_TrustListDataType_init(&trustList);
    if(isTrusted) {
        trustList.specifiedLists = UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES | UA_TRUSTLISTMASKS_TRUSTEDCRLS;
        trustList.trustedCertificates = certificates;
        trustList.trustedCertificatesSize = certificatesSize;
        trustList.trustedCrls = crls;
        trustList.trustedCrlsSize = crlsSize;
    } else {
        trustList.specifiedLists = UA_TRUSTLISTMASKS_ISSUERCERTIFICATES | UA_TRUSTLISTMASKS_ISSUERCRLS;
        trustList.issuerCertificates = certificates;
        trustList.issuerCertificatesSize = certificatesSize;
        trustList.issuerCrls = crls;
        trustList.issuerCrlsSize = crlsSize;
    }

    retval = certGroup->removeFromTrustList(certGroup, &trustList);
    UA_Array_delete(crls, crlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_calloc(1, sizeof(UA_DelayedCallback));
    if(!dc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    dc->callback = secureChannel_delayedCloseTrustList;
    dc->application = server;
    dc->context = dc;

    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, dc);

    return UA_STATUSCODE_GOOD;
}

typedef struct UpdateCertInfo {
    UA_Server *server;
    UA_NodeId certificateTypeId;
} UpdateCertInfo;

static void
secureChannel_delayedClose(void *application, void *context) {
    UA_DelayedCallback *dc = (UA_DelayedCallback*)context;
    UpdateCertInfo *info = (UpdateCertInfo*)application;

    UA_SecureChannel *channel;
    TAILQ_FOREACH(channel, &info->server->channels, serverEntry) {
        const UA_SecurityPolicy *policy = channel->securityPolicy;
        if(UA_NodeId_equal(&policy->certificateTypeId, &(info->certificateTypeId)))
            UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
    }
    UA_NodeId_clear(&(info->certificateTypeId));
    UA_free(info);
    UA_free(dc);
}

UA_StatusCode
UA_Server_updateCertificate(UA_Server *server,
                            const UA_NodeId certificateGroupId,
                            const UA_NodeId certificateTypeId,
                            const UA_ByteString certificate,
                            const UA_ByteString *privateKey) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;

    lockServer(server);

    if(server->gdsManager.transaction.state == UA_GDSTRANSACTIONSTATE_PENDING) {
        unlockServer(server);
        return UA_STATUSCODE_BADTRANSACTIONPENDING;
    }

    UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    UA_NodeId certGroupId = certificateGroupId;
    if(UA_NodeId_isNull(&certGroupId)) {
        /* Use default value if argument is empty */
        certGroupId = defaultApplicationGroup;
    }
    /* The server currently only supports the DefaultApplicationGroup */
    if(!UA_NodeId_equal(&certGroupId, &defaultApplicationGroup)) {
        unlockServer(server);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* The server currently only supports the following certificate type */
    /* UA_NodeId certTypRsaMin = UA_NODEID_NUMERIC(0, UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE); */
    UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
    if(!UA_NodeId_equal(&certificateTypeId, &certTypRsaSha256)) {
        unlockServer(server);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_ByteString newPrivateKey = UA_BYTESTRING_NULL;
    if(privateKey) {
        if(UA_CertificateUtils_checkKeyPair(&certificate, privateKey) != UA_STATUSCODE_GOOD) {
            unlockServer(server);
            return UA_STATUSCODE_BADNOTSUPPORTED;
        }
        newPrivateKey = *privateKey;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < server->config.endpointsSize; i++) {
        UA_EndpointDescription *ed = &server->config.endpoints[i];
        UA_SecurityPolicy *sp = getSecurityPolicyByUri(server,
                            &server->config.endpoints[i].securityPolicyUri);
        UA_CHECK_MEM(sp, unlockServer(server); return UA_STATUSCODE_BADINTERNALERROR);

        if(!UA_NodeId_equal(&sp->certificateTypeId, &certificateTypeId))
            continue;

        retval = sp->updateCertificate(sp, certificate, newPrivateKey);
        if(retval != UA_STATUSCODE_GOOD) {
            unlockServer(server);
            return retval;
        }

        UA_ByteString_clear(&ed->serverCertificate);
        UA_ByteString_copy(&certificate, &ed->serverCertificate);
    }

    UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_calloc(1, sizeof(UA_DelayedCallback));
    if(!dc) {
        unlockServer(server);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UpdateCertInfo *certInfo = (UpdateCertInfo*)UA_calloc(1, sizeof(UpdateCertInfo));
    certInfo->server = server;
    UA_NodeId_copy(&certificateTypeId, &(certInfo->certificateTypeId));

    dc->callback = secureChannel_delayedClose;
    dc->application = certInfo;
    dc->context = dc;

    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, dc);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_createSigningRequest(UA_Server *server,
                               const UA_NodeId certificateGroupId,
                               const UA_NodeId certificateTypeId,
                               const UA_String *subjectName,
                               const UA_Boolean *regenerateKey,
                               const UA_ByteString *nonce,
                               UA_ByteString *csr) {
    if(!server || !csr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    UA_NodeId certGroupId = certificateGroupId;
    if(UA_NodeId_isNull(&certGroupId)) {
        /* Use default value if argument is empty */
        certGroupId = defaultApplicationGroup;
    }
    /* The server currently only supports the DefaultApplicationGroup */
    if(!UA_NodeId_equal(&certGroupId, &defaultApplicationGroup))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* The server currently only supports RSA CertificateType */
    UA_NodeId rsaShaCertificateType = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
    UA_NodeId rsaMinCertificateType = UA_NODEID_NUMERIC(0,UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE);
    if(!UA_NodeId_equal(&certificateTypeId, &rsaShaCertificateType) &&
       !UA_NodeId_equal(&certificateTypeId, &rsaMinCertificateType))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_CertificateGroup certGroup = server->config.secureChannelPKI;

    if(!UA_NodeId_equal(&certGroup.certificateGroupId, &defaultApplicationGroup))
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString *newPrivateKey = NULL;
    if(regenerateKey && *regenerateKey == true)
        newPrivateKey = UA_ByteString_new();

    for(size_t i = 0; i < server->config.endpointsSize; i++) {
        UA_SecurityPolicy *sp =
            getSecurityPolicyByUri(server, &server->config.endpoints[i].securityPolicyUri);
        if(!sp) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }

        if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE)
            continue;

        if(UA_NodeId_equal(&certificateTypeId, &sp->certificateTypeId) &&
           UA_NodeId_equal(&certGroupId, &sp->certificateGroupId)) {
            retval = sp->createSigningRequest(sp, subjectName, nonce,
                                              &UA_KEYVALUEMAP_NULL, csr, newPrivateKey);
            if(retval != UA_STATUSCODE_GOOD)
                goto cleanup;
        }
    }

    UA_ByteString_clear(&server->gdsManager.transaction.localCsrCertificate);
    UA_ByteString_copy(csr, &server->gdsManager.transaction.localCsrCertificate);

cleanup:
    if(newPrivateKey)
    {
        /* wipe private key before freeing its memory */
        UA_ByteString_memZero(newPrivateKey);
        UA_ByteString_delete(newPrivateKey);
    }

    return retval;
}

/***************************/
/* Server lookup functions */
/***************************/

UA_SecurityPolicy *
getSecurityPolicyByUri(const UA_Server *server, const UA_String *securityPolicyUri) {
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
        if(UA_String_equal(securityPolicyUri, &sp->policyUri))
            return sp;
    }
    return NULL;
}

UA_SecurityPolicy *
getSecurityPolicyByPostfix(const UA_Server *server, const UA_String uriPostfix) {
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
        UA_String spPostfix = securityPolicyUriPostfix(sp->policyUri);
        if(UA_String_equal(&uriPostfix, &spPostfix))
            return sp;
    }
    return NULL;
}

/* The local ApplicationUri has to match the certificates of the
 * SecurityPolicies */
static void
verifyServerApplicationUri(const UA_Server *server) {
#if UA_LOGLEVEL <= 400
    const UA_ServerConfig *sc = &server->config;
    for(size_t i = 0; i < sc->securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &sc->securityPolicies[i];
        if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE &&
           sp->localCertificate.length == 0)
            continue;
        UA_StatusCode retval =
            UA_CertificateUtils_verifyApplicationUri(&sp->localCertificate,
                                &sc->applicationDescription.applicationUri);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_SERVER,
                           "The ApplicationUri %S in the server's ApplicationDescription "
                           "does not match the URI specified in the certificate "
                           "for the SecurityPolicy %S",
                           server->config.applicationDescription.applicationUri,
                           sp->policyUri);
        }
    }
#endif
}

UA_ServerStatistics
UA_Server_getStatistics(UA_Server *server) {
    UA_ServerStatistics stat;
    lockServer(server);
    stat.scs = server->secureChannelStatistics;
    UA_ServerDiagnosticsSummaryDataType *sds = &server->serverDiagnosticsSummary;
    stat.ss.currentSessionCount = server->activeSessionCount;
    stat.ss.cumulatedSessionCount = sds->cumulatedSessionCount;
    stat.ss.securityRejectedSessionCount = sds->securityRejectedSessionCount;
    stat.ss.rejectedSessionCount = sds->rejectedSessionCount;
    stat.ss.sessionTimeoutCount = sds->sessionTimeoutCount;
    stat.ss.sessionAbortCount = sds->sessionAbortCount;
    unlockServer(server);
    return stat;
}

/********************/
/* Main Server Loop */
/********************/

#define UA_MAXTIMEOUT 500 /* Max timeout in ms between main-loop iterations */

void
setServerLifecycleState(UA_Server *server, UA_LifecycleState state) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Not state change, nothing to do */
    if(server->state == state)
        return;

    server->state = state; /* Apply the state change */

    /* Call the application notification callback */
    UA_ServerConfig *config = &server->config;
    if(config->globalNotificationCallback || config->lifecycleNotificationCallback) {
        UA_ApplicationNotificationType nt = UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STARTED;
        switch(state) {
        case UA_LIFECYCLESTATE_STOPPED: nt = UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STOPPING; break;
        case UA_LIFECYCLESTATE_STOPPING: nt = UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STOPPING; break;
        default: break;
        }
        if(config->lifecycleNotificationCallback)
            config->lifecycleNotificationCallback(server, nt, UA_KEYVALUEMAP_NULL);
        if(config->globalNotificationCallback)
            config->globalNotificationCallback(server, nt, UA_KEYVALUEMAP_NULL);
    }

    /* Call the (legacy) notification callback */
    if(server->config.notifyLifecycleState)
        server->config.notifyLifecycleState(server, state);
}

UA_LifecycleState
UA_Server_getLifecycleState(UA_Server *server) {
    return server->state;
}

/* Start: Spin up the workers and the network layer and sample the server's
 *        start time.
 * Iterate: Process repeated callbacks and events in the network layer. This
 *          part can be driven from an external main-loop in an event-driven
 *          single-threaded architecture.
 * Stop: Stop workers, finish all callbacks, stop the network layer, clean up */

UA_StatusCode
UA_Server_run_startup(UA_Server *server) {
    if(server == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    UA_ServerConfig *config = &server->config;

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    /* Prominently warn user that fuzzing build is enabled. This will tamper
     * with authentication tokens and other important variables E.g. if fuzzing
     * is enabled, and two clients are connected, subscriptions do not work
     * properly, since the tokens will be overridden to allow easier fuzzing. */
    UA_LOG_FATAL(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Server was built with unsafe fuzzing mode. "
                 "This should only be used for specific fuzzing builds.");
#endif

    if(server->state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "The server has already been started");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check if UserIdentityTokens are defined */
    bool hasUserIdentityTokens = false;
    for(size_t i = 0; i < config->endpointsSize; i++) {
        if(config->endpoints[i].userIdentityTokensSize > 0) {
            hasUserIdentityTokens = true;
            break;
        }
    }
    if(config->accessControl.userTokenPoliciesSize == 0 && hasUserIdentityTokens == false) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                     "The server has no userIdentificationPolicies defined.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Start the EventLoop if not already started */
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_EventLoop *el = config->eventLoop;
    UA_CHECK_MEM_ERROR(el, return UA_STATUSCODE_BADINTERNALERROR,
                       config->logging, UA_LOGCATEGORY_SERVER,
                       "An EventLoop must be configured");

    if(el->state != UA_EVENTLOOPSTATE_STARTED) {
        retVal = el->start(el);
        UA_CHECK_STATUS(retVal, return retVal); /* Errors are logged internally */
    }

    /* Take the server lock */
    lockServer(server);

    /* Does the ApplicationUri match the local certificates? */
    verifyServerApplicationUri(server);

#if UA_MULTITHREADING >= 100
    /* Add regulare callback for async operation processing */
    UA_AsyncManager_start(&server->asyncManager, server);
#endif

    /* Are there enough SecureChannels possible for the max number of sessions? */
    if(config->maxSecureChannels != 0 &&
       (config->maxSessions == 0 || config->maxSessions > config->maxSecureChannels)) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "Maximum SecureChannels count not enough for the "
                       "maximum Sessions count");
    }

    /* Add a regular callback for housekeeping tasks. With a 1s interval. */
    retVal = addRepeatedCallback(server, serverHouseKeeping,
                                 NULL, 1000.0, &server->houseKeepingCallbackId);
    UA_CHECK_STATUS_ERROR(retVal, unlockServer(server); return retVal,
                          config->logging, UA_LOGCATEGORY_SERVER,
                          "Could not create the server housekeeping task");

    /* Ensure that the uri for ns1 is set up from the app description */
    UA_String_clear(&server->namespaces[1]);
    setupNs1Uri(server);

    /* At least one endpoint has to be configured */
    if(config->endpointsSize == 0) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "There has to be at least one endpoint.");
    }

    /* Update Endpoint description */
    for(size_t i = 0; i < config->endpointsSize; ++i) {
        UA_ApplicationDescription_clear(&config->endpoints[i].server);
        UA_ApplicationDescription_copy(&config->applicationDescription,
                                       &config->endpoints[i].server);
    }

    /* Write ServerArray with same ApplicationUri value as NamespaceArray */
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setArray(&var, &config->applicationDescription.applicationUri,
                        1, &UA_TYPES[UA_TYPES_STRING]);
    UA_NodeId serverArray = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY);
    writeValueAttribute(server, serverArray, &var);

    /* Sample the start time and set it to the Server object */
    server->startTime = el->dateTime_now(el);
    UA_Variant_init(&var);
    UA_Variant_setScalar(&var, &server->startTime, &UA_TYPES[UA_TYPES_DATETIME]);
    UA_NodeId startTime =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
    writeValueAttribute(server, startTime, &var);

    /* Start all ServerComponents */
    ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
             startServerComponent, server);

    /* Check that the binary protocol support component have been started */
    UA_ServerComponent *binaryProtocolManager =
        getServerComponentByName(server, UA_STRING("binary"));
    if(!binaryProtocolManager) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                     "Binary protocol support component not found.");
        /* Stop all server components that have already been started */
        ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
                 stopServerComponent, server);
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(binaryProtocolManager->state != UA_LIFECYCLESTATE_STARTED) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                       "The binary protocol support component could not been started.");
        /* Stop all server components that have already been started */
        ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
                 stopServerComponent, NULL);
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Set the server to STARTED. From here on, only use
     * UA_Server_run_shutdown(server) to stop the server. */
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STARTED);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

UA_UInt16
UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) {
    /* Make sure an EventLoop is configured */
    UA_EventLoop *el = server->config.eventLoop;
    if(!el)
        return 0;

    /* Process timed and network events in the EventLoop */
    UA_UInt32 timeout = (waitInternal) ? UA_MAXTIMEOUT : 0;
    el->run(el, timeout);

    /* Return the time until the next scheduled callback */
    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime nextTimeout = (el->nextTimer(el) - now) / UA_DATETIME_MSEC;
    if(nextTimeout < 0)
        nextTimeout = 0;
    if(nextTimeout > UA_UINT16_MAX)
        nextTimeout = UA_UINT16_MAX;
    return (UA_UInt16)nextTimeout;
}

static UA_Boolean
testShutdownCondition(UA_Server *server) {
    /* Was there a wait time until the shutdown configured? */
    if(server->endTime == 0)
        return false;
    UA_EventLoop *el = server->config.eventLoop;
    return (el->dateTime_now(el) > server->endTime);
}

static UA_Boolean
testStoppedCondition(UA_Server *server) {
    /* Check if there are remaining server components that did not fully stop */
    if(ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
                checkServerComponent, NULL) != NULL)
        return false;
    return true;
}

UA_StatusCode
UA_Server_run_shutdown(UA_Server *server) {
    if(server == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);

    if(server->state != UA_LIFECYCLESTATE_STARTED) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "The server is not started, cannot be shut down");
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Set to stopping and notify the application */
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPING);

#if UA_MULTITHREADING >= 100
    /* Stop regular callback for async operation processing */
    UA_AsyncManager_stop(&server->asyncManager, server);
#endif

    /* Stop the regular housekeeping tasks */
    if(server->houseKeepingCallbackId != 0) {
        removeCallback(server, server->houseKeepingCallbackId);
        server->houseKeepingCallbackId = 0;
    }

    /* Stop all ServerComponents */
    ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
             stopServerComponent, NULL);

    /* Are we already stopped? */
    if(testStoppedCondition(server)) {
        setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPED);
    }

    /* Only stop the EventLoop if it is coupled to the server lifecycle  */
    if(server->config.externalEventLoop) {
        unlockServer(server);
        return UA_STATUSCODE_GOOD;
    }

    /* Unlock and do one "normal" iteration. This allows threads waiting for the
     * server lock to proceed before the server lock is destroyed. */
    unlockServer(server);
    UA_Server_run_iterate(server, true);
    lockServer(server);

    /* Iterate the EventLoop until the server is stopped */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_EventLoop *el = server->config.eventLoop;
    while(!testStoppedCondition(server) &&
          res == UA_STATUSCODE_GOOD) {
        res = el->run(el, 100);
    }

    /* Stop the EventLoop. Iterate until stopped. */
    el->stop(el);
    while(el->state != UA_EVENTLOOPSTATE_STOPPED &&
          el->state != UA_EVENTLOOPSTATE_FRESH &&
          res == UA_STATUSCODE_GOOD) {
        res = el->run(el, 100);
    }

    /* Set server lifecycle state to stopped if not already the case */
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPED);

    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_run(UA_Server *server, const volatile UA_Boolean *running) {
    UA_StatusCode retval = UA_Server_run_startup(server);
    UA_CHECK_STATUS(retval, return retval);

    while(!testShutdownCondition(server)) {
        UA_Server_run_iterate(server, true);
        if(!*running) {
            if(setServerShutdown(server))
                break;
        }
    }
    return UA_Server_run_shutdown(server);
}

void lockServer(UA_Server *server) {
    if(UA_LIKELY(server->config.eventLoop && server->config.eventLoop->lock))
        server->config.eventLoop->lock(server->config.eventLoop);
    UA_LOCK(&server->serviceMutex);
}

void unlockServer(UA_Server *server) {
    if(UA_LIKELY(server->config.eventLoop && server->config.eventLoop->unlock))
        server->config.eventLoop->unlock(server->config.eventLoop);
    UA_UNLOCK(&server->serviceMutex);
}

/**** amalgamated original file "/src/server/ua_server_ns0.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Thomas Bender
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2023-2025 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 */


#ifdef UA_GENERATED_NAMESPACE_ZERO
#endif


static UA_StatusCode
ns0_addNode_raw(UA_Server *server, UA_NodeClass nodeClass,
            UA_UInt32 nodeId, char *name, void *attributes,
            const UA_DataType *attributesType) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = nodeClass;
    item.requestedNewNodeId.nodeId = UA_NODEID_NUMERIC(0, nodeId);
    item.browseName = UA_QUALIFIEDNAME(0, name);
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes,
                                        attributes, attributesType);
    return addNode_raw(server, &server->adminSession, NULL, &item, NULL);
}

static UA_StatusCode
ns0_addNode_finish(UA_Server *server, UA_UInt32 nodeId,
               UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId) {
    const UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId);
    const UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId);
    const UA_NodeId targetId = UA_NODEID_NUMERIC(0, parentNodeId);
    UA_StatusCode retval = addRef(server, sourceId, refTypeId, targetId, false);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    return addNode_finish(server, &server->adminSession, &sourceId);
}

static UA_StatusCode
addObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
              UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) {
    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", name);
    return addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(0, objectid),
                   UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid),
                   UA_QUALIFIEDNAME(0, name), UA_NODEID_NUMERIC(0, type_id),
                   &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                   NULL, NULL);
}

static UA_StatusCode
addReferenceTypeNode(UA_Server *server, char* name, char *inverseName, UA_UInt32 referencetypeid,
                     UA_Boolean isabstract, UA_Boolean symmetric, UA_UInt32 parentid) {
    UA_ReferenceTypeAttributes reference_attr = UA_ReferenceTypeAttributes_default;
    reference_attr.displayName = UA_LOCALIZEDTEXT("", name);
    reference_attr.isAbstract = isabstract;
    reference_attr.symmetric = symmetric;
    if(inverseName)
        reference_attr.inverseName = UA_LOCALIZEDTEXT("", inverseName);
    return addNode(server, UA_NODECLASS_REFERENCETYPE, UA_NODEID_NUMERIC(0, referencetypeid),
                   UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, UA_QUALIFIEDNAME(0, name),
                   UA_NODEID_NULL, &reference_attr,
                   &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], NULL, NULL);
}

/***************************/
/* Bootstrap NS0 hierarchy */
/***************************/

/* Creates the basic nodes which are expected by the nodeset compiler to be
 * already created. This is necessary to reduce the dependencies for the nodeset
 * compiler. */
static UA_StatusCode
createNS0_base(UA_Server *server) {
    /* Bootstrap ReferenceTypes. The order of these is important for the
     * ReferenceTypeIndex. The ReferenceTypeIndex is created with the raw node.
     * The ReferenceTypeSet of subtypes for every ReferenceType is created
     * during the call to AddNode_finish. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_ReferenceTypeAttributes references_attr = UA_ReferenceTypeAttributes_default;
    references_attr.displayName = UA_LOCALIZEDTEXT("", "References");
    references_attr.isAbstract = true;
    references_attr.symmetric = true;
    references_attr.inverseName = UA_LOCALIZEDTEXT("", "References");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_REFERENCES, "References",
                           &references_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);

    UA_ReferenceTypeAttributes hassubtype_attr = UA_ReferenceTypeAttributes_default;
    hassubtype_attr.displayName = UA_LOCALIZEDTEXT("", "HasSubtype");
    hassubtype_attr.isAbstract = false;
    hassubtype_attr.symmetric = false;
    hassubtype_attr.inverseName = UA_LOCALIZEDTEXT("", "SubtypeOf");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_HASSUBTYPE, "HasSubtype",
                           &hassubtype_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);

    UA_ReferenceTypeAttributes aggregates_attr = UA_ReferenceTypeAttributes_default;
    aggregates_attr.displayName = UA_LOCALIZEDTEXT("", "Aggregates");
    aggregates_attr.isAbstract = true;
    aggregates_attr.symmetric = false;
    aggregates_attr.inverseName = UA_LOCALIZEDTEXT("", "AggregatedBy");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_AGGREGATES, "Aggregates",
                           &aggregates_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);

    ret |= addReferenceTypeNode(server, "HierarchicalReferences", NULL,
                         UA_NS0ID_HIERARCHICALREFERENCES, true, false, UA_NS0ID_REFERENCES);

    ret |= addReferenceTypeNode(server, "NonHierarchicalReferences", NULL,
                         UA_NS0ID_NONHIERARCHICALREFERENCES, true, true, UA_NS0ID_REFERENCES);

    ret |= addReferenceTypeNode(server, "HasChild", NULL, UA_NS0ID_HASCHILD,
                         true, false, UA_NS0ID_HIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "Organizes", "OrganizedBy", UA_NS0ID_ORGANIZES,
                         false, false, UA_NS0ID_HIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasEventSource", "EventSourceOf", UA_NS0ID_HASEVENTSOURCE,
                         false, false, UA_NS0ID_HIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasModellingRule", "ModellingRuleOf", UA_NS0ID_HASMODELLINGRULE,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasEncoding", "EncodingOf", UA_NS0ID_HASENCODING,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasDescription", "DescriptionOf", UA_NS0ID_HASDESCRIPTION,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasTypeDefinition", "TypeDefinitionOf", UA_NS0ID_HASTYPEDEFINITION,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "GeneratesEvent", "GeneratedBy", UA_NS0ID_GENERATESEVENT,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    /* Complete bootstrap of Aggregates */
    ret |= ns0_addNode_finish(server, UA_NS0ID_AGGREGATES, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE);

    /* Complete bootstrap of HasSubtype */
    ret |= ns0_addNode_finish(server, UA_NS0ID_HASSUBTYPE, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE);

    ret |= addReferenceTypeNode(server, "HasProperty", "PropertyOf", UA_NS0ID_HASPROPERTY,
                         false, false, UA_NS0ID_AGGREGATES);

    ret |= addReferenceTypeNode(server, "HasComponent", "ComponentOf", UA_NS0ID_HASCOMPONENT,
                         false, false, UA_NS0ID_AGGREGATES);

    ret |= addReferenceTypeNode(server, "HasNotifier", "NotifierOf", UA_NS0ID_HASNOTIFIER,
                         false, false, UA_NS0ID_HASEVENTSOURCE);

    ret |= addReferenceTypeNode(server, "HasOrderedComponent", "OrderedComponentOf",
                         UA_NS0ID_HASORDEREDCOMPONENT, false, false, UA_NS0ID_HASCOMPONENT);

    ret |= addReferenceTypeNode(server, "HasInterface", "InterfaceOf",
                         UA_NS0ID_HASINTERFACE, false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    /**************/
    /* Data Types */
    /**************/

    /* Bootstrap BaseDataType */
    UA_DataTypeAttributes basedatatype_attr = UA_DataTypeAttributes_default;
    basedatatype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataType");
    basedatatype_attr.isAbstract = true;
    ret |= ns0_addNode_raw(server, UA_NODECLASS_DATATYPE, UA_NS0ID_BASEDATATYPE, "BaseDataType",
                           &basedatatype_attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]);

    /*****************/
    /* VariableTypes */
    /*****************/

    UA_VariableTypeAttributes basevar_attr = UA_VariableTypeAttributes_default;
    basevar_attr.displayName = UA_LOCALIZEDTEXT("", "BaseVariableType");
    basevar_attr.isAbstract = true;
    basevar_attr.valueRank = UA_VALUERANK_ANY;
    basevar_attr.dataType = UA_NS0ID(BASEDATATYPE);
    ret |= ns0_addNode_raw(server, UA_NODECLASS_VARIABLETYPE,
                           UA_NS0ID_BASEVARIABLETYPE, "BaseVariableType",
                           &basevar_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]);

    UA_VariableTypeAttributes bdv_attr = UA_VariableTypeAttributes_default;
    bdv_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataVariableType");
    bdv_attr.dataType = UA_NS0ID(BASEDATATYPE);
    bdv_attr.valueRank = UA_VALUERANK_ANY;
    ret |= addNode(server, UA_NODECLASS_VARIABLETYPE,
                   UA_NS0ID(BASEDATAVARIABLETYPE), UA_NS0ID(BASEVARIABLETYPE),
                   UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "BaseDataVariableType"),
                   UA_NODEID_NULL, &bdv_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
                   NULL, NULL);

    UA_VariableTypeAttributes prop_attr = UA_VariableTypeAttributes_default;
    prop_attr.displayName = UA_LOCALIZEDTEXT("", "PropertyType");
    prop_attr.dataType = UA_NS0ID(BASEDATATYPE);
    prop_attr.valueRank = UA_VALUERANK_ANY;
    ret |= addNode(server, UA_NODECLASS_VARIABLETYPE,
                   UA_NS0ID(PROPERTYTYPE), UA_NS0ID(BASEVARIABLETYPE),
                   UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "PropertyType"),
                   UA_NODEID_NULL, &prop_attr,
                   &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], NULL, NULL);

    /***************/
    /* ObjectTypes */
    /***************/

    UA_ObjectTypeAttributes baseobj_attr = UA_ObjectTypeAttributes_default;
    baseobj_attr.displayName = UA_LOCALIZEDTEXT("", "BaseObjectType");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_OBJECTTYPE,
                           UA_NS0ID_BASEOBJECTTYPE, "BaseObjectType",
                           &baseobj_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]);

    UA_ObjectTypeAttributes folder_attr = UA_ObjectTypeAttributes_default;
    folder_attr.displayName = UA_LOCALIZEDTEXT("", "FolderType");
    ret |= addNode(server, UA_NODECLASS_OBJECTTYPE,
                   UA_NS0ID(FOLDERTYPE), UA_NS0ID(BASEOBJECTTYPE),
                   UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "FolderType"),
                   UA_NODEID_NULL,
                   &folder_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], NULL, NULL);

    /******************/
    /* Root and below */
    /******************/

    ret |= addObjectNode(server, "Root", UA_NS0ID_ROOTFOLDER, 0, 0, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "Objects", UA_NS0ID_OBJECTSFOLDER, UA_NS0ID_ROOTFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "Types", UA_NS0ID_TYPESFOLDER, UA_NS0ID_ROOTFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "ReferenceTypes", UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_REFERENCES,
                              UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "DataTypes", UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_BASEDATATYPE,
                              UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "VariableTypes", UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_BASEVARIABLETYPE,
                              UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "ObjectTypes", UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_BASEOBJECTTYPE,
                              UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "EventTypes", UA_NS0ID_EVENTTYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "Views", UA_NS0ID_VIEWSFOLDER, UA_NS0ID_ROOTFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    /* Add BaseEventType */
    UA_ObjectTypeAttributes eventtype_attr = UA_ObjectTypeAttributes_default;
    eventtype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseEventType");
    ret |= addNode(server, UA_NODECLASS_OBJECTTYPE, UA_NS0ID(BASEEVENTTYPE),
                   UA_NS0ID(BASEOBJECTTYPE), UA_NODEID_NULL,
                   UA_QUALIFIEDNAME(0, "BaseEventType"), UA_NODEID_NULL, &eventtype_attr,
                   &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], NULL, NULL);
    ret |= addRef(server, UA_NS0ID(EVENTTYPESFOLDER), UA_NS0ID(ORGANIZES),
                  UA_NS0ID(BASEEVENTTYPE), true);

    if(ret != UA_STATUSCODE_GOOD)
        ret = UA_STATUSCODE_BADINTERNALERROR;

    return ret;
}

/****************/
/* Data Sources */
/****************/

static UA_StatusCode
writeStatus(UA_Server *server, const UA_NodeId *sessionId,
            void *sessionContext, const UA_NodeId *nodeId,
            void *nodeContext, const UA_NumericRange *range,
            const UA_DataValue *value) {
    if(range)
        return UA_STATUSCODE_BADINDEXRANGEINVALID;

    if(nodeId->identifier.numeric != UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Only the local user can write into this variable */
    if(sessionId != &server->adminSession.sessionId)
        return UA_STATUSCODE_BADUSERACCESSDENIED;

    if(!UA_Variant_hasScalarType(&value->value, &UA_TYPES[UA_TYPES_UINT32]))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_EventLoop *el = server->config.eventLoop;
    UA_UInt32 *endTime = (UA_UInt32*)value->value.data;
    server->endTime = el->dateTime_now(el) + (UA_DateTime)(*endTime * UA_DATETIME_SEC);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readStatus(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
           const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp,
           const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    if(sourceTimestamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }

    void *data = NULL;

    UA_assert(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC);

    switch(nodeId->identifier.numeric) {
    case UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN: {
        UA_UInt32 *shutdown = UA_UInt32_new();
        if(!shutdown)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        if(server->endTime != 0)
            *shutdown = (UA_UInt32)((server->endTime - el->dateTime_now(el)) / UA_DATETIME_SEC);
        value->value.data = shutdown;
        value->value.type = &UA_TYPES[UA_TYPES_UINT32];
        value->hasValue = true;
        return UA_STATUSCODE_GOOD;
    }

    case UA_NS0ID_SERVER_SERVERSTATUS_STATE: {
        UA_ServerState *state = UA_ServerState_new();
        if(!state)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        if(server->endTime != 0)
            *state = UA_SERVERSTATE_SHUTDOWN;
        value->value.data = state;
        value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
        value->hasValue = true;
        return UA_STATUSCODE_GOOD;
    }

    case UA_NS0ID_SERVER_SERVERSTATUS: {
        UA_ServerStatusDataType *statustype = UA_ServerStatusDataType_new();
        if(!statustype)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        statustype->startTime = server->startTime;
        statustype->currentTime = el->dateTime_now(el);

        statustype->state = UA_SERVERSTATE_RUNNING;
        statustype->secondsTillShutdown = 0;
        if(server->endTime != 0) {
            statustype->state = UA_SERVERSTATE_SHUTDOWN;
            statustype->secondsTillShutdown = (UA_UInt32)
                ((server->endTime - el->dateTime_now(el)) / UA_DATETIME_SEC);
        }

        value->value.data = statustype;
        value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
        value->hasValue = true;
        return UA_BuildInfo_copy(&server->config.buildInfo, &statustype->buildInfo);
    }

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO:
        value->value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
        data = &server->config.buildInfo;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.productUri;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.manufacturerName;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.productName;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.softwareVersion;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.buildNumber;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE:
        value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
        data = &server->config.buildInfo.buildDate;
        break;

    default:
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINTERNALERROR;
        return UA_STATUSCODE_GOOD;
    }

    value->value.data = UA_new(value->value.type);
    if(!value->value.data) {
        value->value.type = NULL;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    value->hasValue = true;
    return UA_copy(data, value->value.data, value->value.type);
}

#ifdef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
readServiceLevel(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                 const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp,
                 const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    value->value.type = &UA_TYPES[UA_TYPES_BYTE];
    value->value.arrayLength = 0;
    UA_Byte *byte = UA_Byte_new();
    if(!byte)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *byte = 255;
    value->value.data = byte;
    value->value.arrayDimensionsSize = 0;
    value->value.arrayDimensions = NULL;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readAuditing(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
             const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp,
             const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
    value->value.arrayLength = 0;
    UA_Boolean *boolean = UA_Boolean_new();
    if(!boolean)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *boolean = false;
    value->value.data = boolean;
    value->value.arrayDimensionsSize = 0;
    value->value.arrayDimensions = NULL;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
readNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp,
               const UA_NumericRange *range,
               UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }
    UA_StatusCode retval;
    retval = UA_Variant_setArrayCopy(&value->value, server->namespaces,
                                     server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeid, void *nodeContext, const UA_NumericRange *range,
                const UA_DataValue *value) {
    /* Check the data type */
    if(!value->hasValue ||
       value->value.type != &UA_TYPES[UA_TYPES_STRING])
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Check that the variant is not empty */
    if(!value->value.data)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* TODO: Writing with a range is not implemented */
    if(range)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_String *newNamespaces = (UA_String*)value->value.data;
    size_t newNamespacesSize = value->value.arrayLength;

    /* Test if we append to the existing namespaces */
    if(newNamespacesSize <= server->namespacesSize)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);

    /* Test if the existing namespaces are unchanged */
    for(size_t i = 0; i < server->namespacesSize; ++i) {
        if(!UA_String_equal(&server->namespaces[i], &newNamespaces[i]))
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Add namespaces */
    for(size_t i = server->namespacesSize; i < newNamespacesSize; ++i)
        addNamespace(server, newNamespaces[i]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readCurrentTime(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeid, void *nodeContext, UA_Boolean sourceTimeStamp,
                const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    UA_DateTime currentTime = el->dateTime_now(el);
    UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, &currentTime,
                                                    &UA_TYPES[UA_TYPES_DATETIME]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    value->hasValue = true;
    if(sourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = currentTime;
    }
    return UA_STATUSCODE_GOOD;
}

#ifdef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
readOperationLimits(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                        const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp,
                        const UA_NumericRange *range,
                        UA_DataValue *value) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(nodeid->identifierType != UA_NODEIDTYPE_NUMERIC)
        return UA_STATUSCODE_BADNOTSUPPORTED;
    switch(nodeid->identifier.numeric) {
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerRead, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerWrite, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerMethodCall, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerBrowse, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerRegisterNodes, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerTranslateBrowsePathsToNodeIds, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerNodeManagement, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxMonitoredItemsPerCall, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMSQUEUESIZE:
#ifdef UA_ENABLE_SUBSCRIPTIONS
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.queueSizeLimits.max,
                                              &UA_TYPES[UA_TYPES_UINT32]);
#else
            {
                UA_UInt32 maxQueueSize = 0;
                retval = UA_Variant_setScalarCopy(&value->value, &maxQueueSize,
                                                  &UA_TYPES[UA_TYPES_UINT32]);
            }
#endif
            break;
        default:
            retval = UA_STATUSCODE_BADNOTSUPPORTED;
    }
    return retval;
}

static UA_StatusCode
readMinSamplingInterval(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp,
               const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode retval;
    UA_Duration minInterval;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    minInterval = server->config.samplingIntervalLimits.min;
#else
    minInterval = 0.0;
#endif
    retval = UA_Variant_setScalarCopy(&value->value, &minInterval, &UA_TYPES[UA_TYPES_DURATION]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}
#endif

#if defined(UA_GENERATED_NAMESPACE_ZERO) && defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
static UA_StatusCode
resendData(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
           const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId,
           void *objectContext, size_t inputSize, const UA_Variant *input,
           size_t outputSize, UA_Variant *output) {
    /* Get the input argument */
    if(inputSize != 1 ||
       !UA_Variant_hasScalarType(input, &UA_TYPES[UA_TYPES_UINT32]))
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data));

    /* Get the Session */
    lockServer(server);
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Get the Subscription */
    UA_Subscription *subscription = getSubscriptionById(server, subscriptionId);
    if(!subscription) {
        unlockServer(server);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* The Subscription is not attached to this Session */
    if(subscription->session != session) {
        unlockServer(server);
        return UA_STATUSCODE_BADUSERACCESSDENIED;
    }

    UA_Subscription_resendData(server, subscription);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}
static UA_StatusCode
readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                   const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId,
                   void *objectContext, size_t inputSize, const UA_Variant *input,
                   size_t outputSize, UA_Variant *output) {
    /* Return two empty arrays by default */
    UA_Variant_setArray(&output[0], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]),
                        0, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setArray(&output[1], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]),
                        0, &UA_TYPES[UA_TYPES_UINT32]);

    lockServer(server);

    /* Get the Session */
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(inputSize == 0 || !input[0].data) {
        unlockServer(server);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* Get the Subscription */
    UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data));
    UA_Subscription *subscription = getSubscriptionById(server, subscriptionId);
    if(!subscription) {
        unlockServer(server);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* The Subscription is not attached to this Session */
    if(subscription->session != session) {
        unlockServer(server);
        return UA_STATUSCODE_BADUSERACCESSDENIED;
    }

    /* Count the MonitoredItems */
    UA_UInt32 sizeOfOutput = 0;
    UA_MonitoredItem* monitoredItem;
    LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) {
        ++sizeOfOutput;
    }
    if(sizeOfOutput == 0) {
        unlockServer(server);
        return UA_STATUSCODE_GOOD;
    }

    /* Allocate the output arrays */
    UA_UInt32 *clientHandles = (UA_UInt32*)
        UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
    if(!clientHandles) {
        unlockServer(server);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    UA_UInt32 *serverHandles = (UA_UInt32*)
        UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
    if(!serverHandles) {
        unlockServer(server);
        UA_free(clientHandles);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Fill the array */
    UA_UInt32 i = 0;
    LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) {
        clientHandles[i] = monitoredItem->parameters.clientHandle;
        serverHandles[i] = monitoredItem->monitoredItemId;
        ++i;
    }
    UA_Variant_setArray(&output[0], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setArray(&output[1], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}
#endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */

static UA_StatusCode
writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v,
                      size_t length, const UA_DataType *type) {
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setArray(&var, v, length, type);
    return writeValueAttribute(server, UA_NODEID_NUMERIC(0, id), &var);
}

#ifdef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
writeNs0Variable(UA_Server *server, UA_UInt32 id, void *v, const UA_DataType *type) {
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setScalar(&var, v, type);
    return writeValueAttribute(server, UA_NODEID_NUMERIC(0, id), &var);
}
#endif

#ifndef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
addVariableNode(UA_Server *server, char* name, UA_UInt32 variableid,
                UA_UInt32 parentid, UA_UInt32 referenceid,
                UA_Int32 valueRank, UA_UInt32 dataType) {
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT("", name);
    attr.dataType = UA_NODEID_NUMERIC(0, dataType);
    attr.valueRank = valueRank;
    attr.accessLevel = UA_ACCESSLEVELMASK_READ;
    return addNode(server, UA_NODECLASS_VARIABLE, UA_NODEID_NUMERIC(0, variableid),
                   UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid),
                   UA_QUALIFIEDNAME(0, name), UA_NS0ID(BASEDATAVARIABLETYPE),
                   &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL, NULL);
}

/* A minimal server object that is not complete and does not use the mandated
 * references to a server type. To be used on very constrained devices. */
static UA_StatusCode
minimalServerObject(UA_Server *server) {
    /* Server */
    UA_StatusCode retval = addObjectNode(server, "Server", UA_NS0ID_SERVER, UA_NS0ID_OBJECTSFOLDER,
                                         UA_NS0ID_ORGANIZES, UA_NS0ID_BASEOBJECTTYPE);

    /* Use a valuerank of -2 for now. The array is added later on and the valuerank set to 1. */
    retval |= addVariableNode(server, "ServerArray", UA_NS0ID_SERVER_SERVERARRAY,
                              UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY,
                              UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "NamespaceArray", UA_NS0ID_SERVER_NAMESPACEARRAY,
                              UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY,
                              UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ServerStatus", UA_NS0ID_SERVER_SERVERSTATUS,
                              UA_NS0ID_SERVER, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "StartTime", UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "CurrentTime", UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "State", UA_NS0ID_SERVER_SERVERSTATUS_STATE,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "BuildInfo", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ProductUri", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ManufacturerName",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ProductName",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "SoftwareVersion",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "BuildNumber",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "BuildDate",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    return retval;
}

#else

static void
addModellingRules(UA_Server *server) {
    /* Test if the ModellingRules folder was added. (Only for the full ns0.) */
    UA_NodeId mrNodeId = UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES);
    const UA_Node *mrnode = UA_NODESTORE_GET(server, &mrNodeId);
    if(!mrnode)
        return;
    UA_NODESTORE_RELEASE(server, mrnode);

    /* Add ExposesItsArray */
    addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_EXPOSESITSARRAY), true);

    /* Add Mandatory */
    addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_MANDATORY), true);


    /* Add MandatoryPlaceholder */
    addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_MANDATORYPLACEHOLDER), true);

    /* Add Optional */
    addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_OPTIONAL), true);

    /* Add OptionalPlaceholder */
    addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_OPTIONALPLACEHOLDER), true);
}

#endif

static UA_StatusCode connectNS0_dataSources(UA_Server *server);
static UA_StatusCode configureNS0(UA_Server *server);

/* Initialize the nodeset 0 by using the generated code of the nodeset compiler.
 * This also initialized the data sources for various variables, such as for
 * example server time. */
UA_StatusCode
initNS0(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Initialize base nodes which are always required an cannot be created
     * through the NS compiler */
    server->bootstrapNS0 = true;
    UA_StatusCode retVal = createNS0_base(server);

#ifdef UA_GENERATED_NAMESPACE_ZERO
    /* Load nodes and references generated from the XML ns0 definition */
    retVal |= namespace0_generated(server);
#else
    /* Create a minimal server object */
    retVal |= minimalServerObject(server);
#endif

    server->bootstrapNS0 = false;

    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Initialization of Namespace 0 failed with %s. "
                     "See previous outputs for any error messages.",
                     UA_StatusCode_name(retVal));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Connect data sources and configure NS0 (shared with ROM nodestore) */
    retVal |= connectNS0_dataSources(server);
    retVal |= configureNS0(server);

    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Initialization of Namespace 0 (after bootstrapping) "
                     "failed with %s. See previous outputs for any error messages.",
                     UA_StatusCode_name(retVal));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

/* Configure NS0 nodes: write values, delete unused nodes, add references.
 * This is called after nodes are created (initNS0) or loaded from ROM.
 * Shared between initNS0() and initNS0_dataSources() to avoid duplication. */
static UA_StatusCode
configureNS0(UA_Server *server) {
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;

    /* Additional attribute setup for NamespaceArray */
    retVal |= writeValueRankAttribute(server, UA_NS0ID(SERVER_NAMESPACEARRAY), 1);

    /* ServerArray */
    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY,
                                    &server->config.applicationDescription.applicationUri,
                                    1, &UA_TYPES[UA_TYPES_STRING]);
    retVal |= writeValueRankAttribute(server, UA_NS0ID(SERVER_SERVERARRAY), 1);

    /* StartTime will be sampled in UA_Server_run_startup()*/

    /* CurrentTime - additional attribute setup */
    UA_NodeId currTime = UA_NS0ID(SERVER_SERVERSTATUS_CURRENTTIME);
    retVal |= writeMinimumSamplingIntervalAttribute(server, currTime, 100.0);

#ifdef UA_GENERATED_NAMESPACE_ZERO

    /* ShutDownReason */
    UA_LocalizedText shutdownReason;
    UA_LocalizedText_init(&shutdownReason);
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON,
                               &shutdownReason, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

    /* ServerDiagnostics - EnabledFlag */
#ifdef UA_ENABLE_DIAGNOSTICS
    UA_Boolean enabledFlag = true;
#else
    UA_Boolean enabledFlag = false;
#endif
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG,
                               &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* According to Specification part-5 - pg.no-11(PDF pg.no-29), when the
     * ServerDiagnostics is disabled the client may modify the value of
     * enabledFlag=true in the server. By default, this node have
     * CurrentRead/Write access. In CTT, Subscription_Minimum_1/002.js test will
     * modify the above flag. This will not be a problem when build
     * configuration is set at UA_NAMESPACE_ZERO="REDUCED" as NodeIds will not
     * be present. When UA_NAMESPACE_ZERO="FULL", the test will fail. Hence made
     * the NodeId as read only */
    retVal |= writeAccessLevelAttribute(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
                                        UA_ACCESSLEVELMASK_READ);

    /* Redundancy Support */
    UA_RedundancySupport redundancySupport = UA_REDUNDANCYSUPPORT_NONE;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT,
                               &redundancySupport, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]);
    /* Remove unused subtypes of ServerRedundancy */
    deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_CURRENTSERVERID), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_REDUNDANTSERVERARRAY), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_SERVERURIARRAY), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_SERVERNETWORKGROUPS), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_CONFORMANCEUNITS), true);
    deleteNode(server, UA_NS0ID(SERVER_URISVERSION), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_CONFORMANCEUNITS), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMS), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMSPERSUBSCRIPTION), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSELECTCLAUSEPARAMETERS), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSESSIONS), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSUBSCRIPTIONS), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSUBSCRIPTIONSPERSESSION), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXWHERECLAUSEPARAMETERS), true);

    /* ServerCapabilities - LocaleIdArray */
    UA_LocaleId locale_en = UA_STRING("en");
    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY,
                                    &locale_en, 1, &UA_TYPES[UA_TYPES_LOCALEID]);

    /* ServerCapabilities - MaxBrowseContinuationPoints */
    UA_UInt16 maxBrowseContinuationPoints = UA_MAXCONTINUATIONPOINTS;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS,
                               &maxBrowseContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);

    /* ServerProfileArray */
    UA_String profileArray[3];
    UA_UInt16 profileArraySize = 0;
#define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING(x)
    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/StandardUA2017");
#ifdef UA_ENABLE_NODEMANAGEMENT
    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement");
#endif
#ifdef UA_ENABLE_METHODCALLS
    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods");
#endif
    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY,
                                    profileArray, profileArraySize, &UA_TYPES[UA_TYPES_STRING]);

    /* ServerCapabilities - MaxQueryContinuationPoints */
    UA_UInt16 maxQueryContinuationPoints = 0;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS,
                               &maxQueryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);

    /* ServerCapabilities - MaxHistoryContinuationPoints */
    UA_UInt16 maxHistoryContinuationPoints = 0;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS,
                               &maxHistoryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);

    /* Remove unused operation limit components */
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADDATA), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADEVENTS), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEDATA), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEEVENTS), true);
#ifndef UA_NODESET_INJECTOR_NEEDS_ROLESET
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_ROLESET), true);
#endif
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSTRINGLENGTH), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXARRAYLENGTH), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXBYTESTRINGLENGTH), true);

    /* Remove not supported server configurations */
    deleteNode(server, UA_NS0ID(SERVER_ESTIMATEDRETURNTIME), true);
    deleteNode(server, UA_NS0ID(SERVER_LOCALTIME), true);
    deleteNode(server, UA_NS0ID(SERVER_REQUESTSERVERSTATECHANGE), true);
    deleteNode(server, UA_NS0ID(SERVER_SETSUBSCRIPTIONDURABLE), true);
    deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTHTTPSGROUP), true);
#ifdef UA_NS0ID_SERVERLOG
    deleteNode(server, UA_NS0ID(SERVERLOG), true);
#endif
#ifdef UA_NS0ID_LLDP
    deleteNode(server, UA_NS0ID(LLDP), true);
#endif
    deleteNode(server, UA_NS0ID(PROVISIONABLEDEVICE), true);
    deleteNode(server, UA_NS0ID(USERMANAGEMENT), true);
    deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_TRANSACTIONDIAGNOSTICS), true);
#ifdef UA_NS0ID_SERVERCONFIGURATION_CONFIGURATIONFILE
    deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_CONFIGURATIONFILE), true);
#endif
#ifndef UA_ENABLE_GDS_PUSHMANAGEMENT
    deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP), true);
    deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP), true);
#endif

#ifndef UA_ENABLE_DIAGNOSTICS
    /* Removing these NodeIds make Server Object to be non-complaint with UA
     * 1.03 in CTT (Base Inforamtion/Base Info Core Structure/ 001.js) In the
     * 1.04 specification this has been resolved by allowing to remove these
     * static nodes as well */
    deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), true);
    deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), true);
#endif

    /* The sampling diagnostics array is optional
     * TODO: Add support for this diagnostics */
    deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SAMPLINGINTERVALDIAGNOSTICSARRAY), true);

#ifndef UA_ENABLE_PUBSUB
    deleteNode(server, UA_NS0ID(PUBLISHSUBSCRIBE), true);
#endif

    /* ServerConfiguration - MulticastDnsEnabled */
#ifdef UA_GENERATED_NAMESPACE_ZERO_FULL
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVERCONFIGURATION_MULTICASTDNSENABLED,
                               &server->config.mdnsEnabled, &UA_TYPES[UA_TYPES_BOOLEAN]);
#else
    {
        UA_Boolean mdnsEnabled = false;
        retVal |= writeNs0Variable(server, UA_NS0ID_SERVERCONFIGURATION_MULTICASTDNSENABLED,
                                   &mdnsEnabled, &UA_TYPES[UA_TYPES_BOOLEAN]);
    }
#endif
#endif

#ifdef UA_GENERATED_NAMESPACE_ZERO_FULL
    /* ServerConfiguration - HasSecureElement */
    {
        UA_Boolean hasSecureElement = false;
        retVal |= writeNs0Variable(server, UA_NS0ID_SERVERCONFIGURATION_HASSECUREELEMENT,
                                   &hasSecureElement, &UA_TYPES[UA_TYPES_BOOLEAN]);
    }
    /* ServerConfiguration - ApplicationType */
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVERCONFIGURATION_APPLICATIONTYPE,
                               &server->config.applicationDescription.applicationType,
                               &UA_TYPES[UA_TYPES_APPLICATIONTYPE]);
    /* OPCUANamespaceMetadata - DefaultAccessRestrictions */
    {
        UA_AccessRestrictionType defaultAccessRestrictions = UA_ACCESSRESTRICTIONTYPE_NONE;
        retVal |= writeNs0Variable(server, UA_NS0ID_OPCUANAMESPACEMETADATA_DEFAULTACCESSRESTRICTIONS,
                                   &defaultAccessRestrictions,
                                   &UA_TYPES[UA_TYPES_ACCESSRESTRICTIONTYPE]);
    }
#endif
#ifndef UA_ENABLE_HISTORIZING
    deleteNode(server, UA_NS0ID(HISTORYSERVERCAPABILITIES), true);
#ifdef UA_NS0ID_DEFAULTHACONFIGURATION
    deleteNode(server, UA_NS0ID(DEFAULTHACONFIGURATION), true);
#endif
#else
    /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYDATACAPABILITY,
                               &server->config.accessHistoryDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - MaxReturnDataValues */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNDATAVALUES,
                               &server->config.maxReturnDataValues, &UA_TYPES[UA_TYPES_UINT32]);

    /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryEventsCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYEVENTSCAPABILITY,
                               &server->config.accessHistoryEventsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - MaxReturnEventValues */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNEVENTVALUES,
                               &server->config.maxReturnEventValues, &UA_TYPES[UA_TYPES_UINT32]);

    /* ServerCapabilities - HistoryServerCapabilities - InsertDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTDATACAPABILITY,
                               &server->config.insertDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - InsertEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTEVENTCAPABILITY,
                               &server->config.insertEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - InsertAnnotationsCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTANNOTATIONCAPABILITY,
                               &server->config.insertAnnotationsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - ReplaceDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEDATACAPABILITY,
                               &server->config.replaceDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - ReplaceEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEEVENTCAPABILITY,
                               &server->config.replaceEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - UpdateDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEDATACAPABILITY,
                               &server->config.updateDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - UpdateEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEEVENTCAPABILITY,
                               &server->config.updateEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - DeleteRawCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETERAWCAPABILITY,
                               &server->config.deleteRawCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - DeleteEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEEVENTCAPABILITY,
                               &server->config.deleteEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - DeleteAtTimeDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEATTIMECAPABILITY,
                               &server->config.deleteAtTimeDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

#ifdef UA_GENERATED_NAMESPACE_ZERO_FULL
    /* HistoryServerCapabilities - ServerTimestampSupported */
    {
        UA_Boolean serverTimestampSupported = true;
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_HISTORYSERVERCAPABILITIES_SERVERTIMESTAMPSUPPORTED,
                                   &serverTimestampSupported, &UA_TYPES[UA_TYPES_BOOLEAN]);
    }
#endif

    /* DefaultHAConfiguration */
#ifdef UA_NS0ID_DEFAULTHACONFIGURATION_STEPPED
    {
        UA_Boolean bTrue = true, bFalse = false;
        UA_Byte percentDataBad = 100, percentDataGood = 100;
        UA_Duration zeroDuration = 0.0;
        UA_Double zeroDouble = 0.0;
        UA_UInt32 zeroUInt32 = 0;
        UA_ExceptionDeviationFormat absValue = UA_EXCEPTIONDEVIATIONFORMAT_ABSOLUTEVALUE;

        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_AGGREGATECONFIGURATION_TREATUNCERTAINASBAD,
                                   &bTrue, &UA_TYPES[UA_TYPES_BOOLEAN]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_AGGREGATECONFIGURATION_PERCENTDATABAD,
                                   &percentDataBad, &UA_TYPES[UA_TYPES_BYTE]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_AGGREGATECONFIGURATION_PERCENTDATAGOOD,
                                   &percentDataGood, &UA_TYPES[UA_TYPES_BYTE]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_AGGREGATECONFIGURATION_USESLOPEDEXTRAPOLATION,
                                   &bFalse, &UA_TYPES[UA_TYPES_BOOLEAN]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_STEPPED,
                                   &bFalse, &UA_TYPES[UA_TYPES_BOOLEAN]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_MAXTIMEINTERVAL,
                                   &zeroDuration, &UA_TYPES[UA_TYPES_DOUBLE]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_MINTIMEINTERVAL,
                                   &zeroDuration, &UA_TYPES[UA_TYPES_DOUBLE]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_EXCEPTIONDEVIATION,
                                   &zeroDouble, &UA_TYPES[UA_TYPES_DOUBLE]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_EXCEPTIONDEVIATIONFORMAT,
                                   &absValue, &UA_TYPES[UA_TYPES_EXCEPTIONDEVIATIONFORMAT]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_SERVERTIMESTAMPSUPPORTED,
                                   &bTrue, &UA_TYPES[UA_TYPES_BOOLEAN]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_MAXTIMESTOREDVALUES,
                                   &zeroDuration, &UA_TYPES[UA_TYPES_DOUBLE]);
        retVal |= writeNs0Variable(server,
                                   UA_NS0ID_DEFAULTHACONFIGURATION_MAXCOUNTSTOREDVALUES,
                                   &zeroUInt32, &UA_TYPES[UA_TYPES_UINT32]);
    }
#endif
#endif

    /* The HasComponent references to the ModellingRules are not part of the
     * Nodeset2.xml. So we add the references manually. */
    addModellingRules(server);

#endif /* UA_GENERATED_NAMESPACE_ZERO */

    return retVal;
}

/* Connect data sources and callbacks to existing NS0 nodes.
 * This is used when NS0 is loaded from an external source (e.g., ROM nodestore)
 * and we only need to attach the dynamic data sources without creating nodes.
 * Also called by initNS0() after node creation to avoid code duplication. */
static UA_StatusCode
connectNS0_dataSources(UA_Server *server) {
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;

    /* NamespaceArray - dynamic callback */
    UA_CallbackValueSource namespaceDataSource = {readNamespaces, writeNamespaces};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_NAMESPACEARRAY),
                                                  namespaceDataSource);

    /* ServerStatus - dynamic callback */
    UA_CallbackValueSource serverStatus = {readStatus, writeStatus};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS), serverStatus);

    /* CurrentTime */
    UA_CallbackValueSource currentTime = {readCurrentTime, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_CURRENTTIME), currentTime);

    /* State */
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_STATE), serverStatus);

    /* BuildInfo and sub-components */
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO), serverStatus);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI), serverStatus);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME), serverStatus);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME), serverStatus);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION), serverStatus);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER), serverStatus);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE), serverStatus);

#ifdef UA_GENERATED_NAMESPACE_ZERO
    /* SecondsTillShutdown */
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN), serverStatus);

    /* ServiceLevel */
    UA_CallbackValueSource serviceLevel = {readServiceLevel, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVICELEVEL), serviceLevel);

    /* Auditing */
    UA_CallbackValueSource auditing = {readAuditing, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_AUDITING), auditing);

    /* MinSupportedSampleRate */
    UA_CallbackValueSource samplingInterval = {readMinSamplingInterval, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE), samplingInterval);

    /* OperationLimits */
    UA_CallbackValueSource operationLimitRead = {readOperationLimits, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL), operationLimitRead);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMSQUEUESIZE), operationLimitRead);

#ifdef UA_ENABLE_DIAGNOSTICS
    /* ServerDiagnostics */
    UA_CallbackValueSource serverDiagSummary = {readDiagnostics, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SERVERVIEWCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDSESSIONCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDSESSIONCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONTIMEOUTCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONABORTCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSUBSCRIPTIONCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSUBSCRIPTIONCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_PUBLISHINGINTERVALCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDREQUESTSCOUNT), serverDiagSummary);
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDREQUESTSCOUNT), serverDiagSummary);

#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_CallbackValueSource serverSubDiagSummary = {readSubscriptionDiagnosticsArray, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), serverSubDiagSummary);
#endif

    UA_CallbackValueSource sessionDiagSummary = {readSessionDiagnosticsArray, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONDIAGNOSTICSARRAY), sessionDiagSummary);

    UA_CallbackValueSource sessionSecDiagSummary = {readSessionSecurityDiagnostics, NULL};
    retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONSECURITYDIAGNOSTICSARRAY), sessionSecDiagSummary);
#endif /* UA_ENABLE_DIAGNOSTICS */

#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
    retVal |= setMethodNode_callback(server, UA_NS0ID(SERVER_GETMONITOREDITEMS), readMonitoredItems);
    retVal |= setMethodNode_callback(server, UA_NS0ID(SERVER_RESENDDATA), resendData);
#endif

#endif /* UA_GENERATED_NAMESPACE_ZERO */

    return retVal;
}

/* Public function for external nodestores (e.g., ROM nodestore) that have
 * NS0 pre-loaded and only need to connect the dynamic data sources and
 * configure values/deletions. */
UA_StatusCode
initNS0_dataSources(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "Configuring pre-loaded NS0 nodes (data sources, values, deletions)");

    /* Connect all data source callbacks (shared with initNS0) */
    UA_StatusCode retVal = connectNS0_dataSources(server);

    /* Configure NS0: write values, delete unused nodes, add references */
    retVal |= configureNS0(server);

    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Some NS0 configuration operations failed: %s "
                       "(this may be normal if some nodes don't exist in ROM)",
                       UA_StatusCode_name(retVal));
        /* Don't fail - some nodes may simply not exist in the ROM */
    }

    return UA_STATUSCODE_GOOD;
}


/**** amalgamated original file "/src/server/ua_server_ns0_diagnostics.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_DIAGNOSTICS

static UA_Boolean
equalBrowseName(UA_String *bn, char *n) {
    UA_String name = UA_STRING(n);
    return UA_String_equal(bn, &name);
}

#ifdef UA_ENABLE_SUBSCRIPTIONS

static const UA_NodeId subDiagArray = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY}};

/****************************/
/* Subscription Diagnostics */
/****************************/

static void
fillSubscriptionDiagnostics(UA_Subscription *sub,
                            UA_SubscriptionDiagnosticsDataType *diag) {
    UA_NodeId_copy(&sub->session->sessionId, &diag->sessionId); /* ignore status */
    diag->subscriptionId = sub->subscriptionId;
    diag->priority = sub->priority;
    diag->publishingInterval = sub->publishingInterval;
    diag->maxKeepAliveCount = sub->maxKeepAliveCount;
    diag->maxLifetimeCount = sub->lifeTimeCount;
    diag->maxNotificationsPerPublish = sub->notificationsPerPublish;
    diag->publishingEnabled = (sub->state > UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH);
    diag->modifyCount = sub->modifyCount;
    diag->enableCount = sub->enableCount;
    diag->disableCount = sub->disableCount;
    diag->republishRequestCount = sub->republishRequestCount;
    diag->republishMessageRequestCount =
        sub->republishRequestCount; /* Always equal to the previous republishRequestCount */
    diag->republishMessageCount = sub->republishMessageCount;
    diag->transferRequestCount = sub->transferRequestCount;
    diag->transferredToAltClientCount = sub->transferredToAltClientCount;
    diag->transferredToSameClientCount = sub->transferredToSameClientCount;
    diag->publishRequestCount = sub->publishRequestCount;
    diag->dataChangeNotificationsCount = sub->dataChangeNotificationsCount;
    diag->eventNotificationsCount = sub->eventNotificationsCount;
    diag->notificationsCount = sub->notificationsCount;
    diag->latePublishRequestCount = sub->latePublishRequestCount;
    diag->currentKeepAliveCount = sub->currentKeepAliveCount;
    diag->currentLifetimeCount = sub->currentLifetimeCount;
    diag->unacknowledgedMessageCount = (UA_UInt32)sub->retransmissionQueueSize;
    diag->discardedMessageCount = sub->discardedMessageCount;
    diag->monitoredItemCount = sub->monitoredItemsSize;
    diag->monitoringQueueOverflowCount = sub->monitoringQueueOverflowCount;
    diag->nextSequenceNumber = sub->nextSequenceNumber;
    diag->eventQueueOverflowCount = sub->eventQueueOverflowCount;

    /* Count the disabled MonitoredItems */
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        if(mon->monitoringMode == UA_MONITORINGMODE_DISABLED)
            diag->disabledMonitoredItemCount++;
    }
}

/* The node context points to the subscription */
static UA_StatusCode
readSubscriptionDiagnostics(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *nodeId, void *nodeContext,
                            UA_Boolean sourceTimestamp,
                            const UA_NumericRange *range, UA_DataValue *value) {
    /* Check the Subscription pointer */
    UA_Subscription *sub = (UA_Subscription*)nodeContext;
    if(!sub)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Read the BrowseName */
    UA_QualifiedName bn;
    UA_StatusCode res = UA_Server_readBrowseName(server, *nodeId, &bn);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Set the value */
    UA_SubscriptionDiagnosticsDataType sddt;
    UA_SubscriptionDiagnosticsDataType_init(&sddt);
    fillSubscriptionDiagnostics(sub, &sddt);

    char memberName[128];
    memcpy(memberName, bn.name.data, bn.name.length);
    memberName[bn.name.length] = 0;

    size_t memberOffset;
    const UA_DataType *memberType;
    UA_Boolean isArray;
    UA_Boolean found =
        UA_DataType_getStructMember(&UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE],
                                    memberName, &memberOffset, &memberType, &isArray);
    if(!found) {
        /* Not the member, but the main subscription diagnostics variable... */
        memberOffset = 0;
        memberType = &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE];
    }

    void *content = (void*)(((uintptr_t)&sddt) + memberOffset);
    res = UA_Variant_setScalarCopy(&value->value, content, memberType);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        value->hasValue = true;

    UA_SubscriptionDiagnosticsDataType_clear(&sddt);
    UA_QualifiedName_clear(&bn);
    return res;
}

/* Return all subscriptions in the server. */
UA_StatusCode
readSubscriptionDiagnosticsArray(UA_Server *server,
                                 const UA_NodeId *sessionId, void *sessionContext,
                                 const UA_NodeId *nodeId, void *nodeContext,
                                 UA_Boolean sourceTimestamp,
                                 const UA_NumericRange *range, UA_DataValue *value) {
    lockServer(server);

    /* Get the current session */
    size_t sdSize = 0;
    session_list_entry *sentry;
    LIST_FOREACH(sentry, &server->sessions, pointers) {
        sdSize += sentry->session.subscriptionsSize;
    }

    /* Allocate the output array */
    UA_SubscriptionDiagnosticsDataType *sd = (UA_SubscriptionDiagnosticsDataType*)
        UA_Array_new(sdSize, &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);
    if(!sd) {
        unlockServer(server);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Collect the statistics */
    size_t i = 0;
    UA_Subscription *sub;
    LIST_FOREACH(sentry, &server->sessions, pointers) {
        TAILQ_FOREACH(sub, &sentry->session.subscriptions, sessionListEntry) {
            fillSubscriptionDiagnostics(sub, &sd[i]);
            i++;
        }
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, sdSize,
                        &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

void
createSubscriptionObject(UA_Server *server, UA_Session *session,
                         UA_Subscription *sub) {
    UA_ExpandedNodeId *children = NULL;
    size_t childrenSize = 0;
    UA_ReferenceTypeSet refTypes;
    UA_NodeId hasComponent = UA_NS0ID(HASCOMPONENT);

    char subIdStr[32];
    itoaUnsigned(sub->subscriptionId, subIdStr, 10);

    /* Find the NodeId of the SubscriptionDiagnosticsArray */
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = sub->session->sessionId;
    UA_RelativePathElement rpe[1];
    memset(rpe, 0, sizeof(UA_RelativePathElement) * 1);
    rpe[0].targetName = UA_QUALIFIEDNAME(0, "SubscriptionDiagnosticsArray");
    bp.relativePath.elements = rpe;
    bp.relativePath.elementsSize = 1;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.targetsSize < 1)
        return;

    /* Create an object for the subscription. Instantiates all the mandatory
     * children. */
    UA_VariableAttributes var_attr = UA_VariableAttributes_default;
    var_attr.valueRank = -1;
    var_attr.displayName.text = UA_STRING(subIdStr);
    var_attr.dataType = UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE].typeId;
    UA_NodeId refId = UA_NS0ID(HASCOMPONENT);
    UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, subIdStr);
    UA_NodeId typeId = UA_NS0ID(SUBSCRIPTIONDIAGNOSTICSTYPE);
    UA_CallbackValueSource subDiagSource = {readSubscriptionDiagnostics, NULL};

    /* Assign a random free NodeId */
    UA_StatusCode res = addNode(server, UA_NODECLASS_VARIABLE, UA_NODEID_NUMERIC(1, 0),
                                bpr.targets[0].targetId.nodeId,
                                refId, browseName, typeId, &var_attr,
                                &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL,
                                &sub->ns0Id);
    UA_CHECK_STATUS(res, goto cleanup);

    /* Add a second reference from the overall SubscriptionDiagnosticsArray variable */
    res = addRefWithSession(server, session,  &subDiagArray, &refId, &sub->ns0Id, true);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Get all children (including the variable itself) and set the contenxt + callback */
    res = referenceTypeIndices(server, &hasComponent, &refTypes, false);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
        res = browseRecursive(server, 1, &sub->ns0Id,
                              UA_BROWSEDIRECTION_FORWARD, &refTypes,
                              UA_NODECLASS_VARIABLE, true, &childrenSize, &children);
    }
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Add the callback to all variables  */
    for(size_t i = 0; i < childrenSize; i++) {
        setVariableNode_callbackValueSource(server, children[i].nodeId, subDiagSource);
        setNodeContext(server, children[i].nodeId, sub);
    }

    UA_Array_delete(children, childrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);

 cleanup:
    UA_BrowsePathResult_clear(&bpr);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Creating the subscription diagnostics object failed "
                               "with StatusCode %s", UA_StatusCode_name(res));
    }
}

/***********************/
/* Session Diagnostics */
/***********************/

static UA_StatusCode
setSessionSubscriptionDiagnostics(UA_Server *server, UA_Session *session,
                                  UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get the current session */
    size_t sdSize = session->subscriptionsSize;

    /* Allocate the output array */
    UA_SubscriptionDiagnosticsDataType *sd = (UA_SubscriptionDiagnosticsDataType*)
        UA_Array_new(sdSize, &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);
    if(!sd)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Collect the statistics */
    size_t i = 0;
    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        fillSubscriptionDiagnostics(sub, &sd[i]);
        i++;
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, sdSize,
                        &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

static void
setSessionDiagnostics(UA_Session *session, UA_SessionDiagnosticsDataType *sd) {
    UA_SessionDiagnosticsDataType_copy(&session->diagnostics, sd);
    UA_NodeId_copy(&session->sessionId, &sd->sessionId);
    UA_String_copy(&session->sessionName, &sd->sessionName);
    UA_ApplicationDescription_copy(&session->clientDescription,
                                   &sd->clientDescription);
    sd->maxResponseMessageSize = session->maxResponseMessageSize;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    sd->currentPublishRequestsInQueue = (UA_UInt32)session->responseQueueSize;
#endif
    sd->actualSessionTimeout = session->timeout;

    /* Set LocaleIds */
    UA_StatusCode res =
        UA_Array_copy(session->localeIds, session->localeIdsSize,
                      (void **)&sd->localeIds, &UA_TYPES[UA_TYPES_STRING]);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        sd->localeIdsSize = session->localeIdsSize;

        /* Set Subscription diagnostics */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    sd->currentSubscriptionsCount = (UA_UInt32)session->subscriptionsSize;

    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        sd->currentMonitoredItemsCount += (UA_UInt32)sub->monitoredItemsSize;
    }
#endif
}

UA_StatusCode
readSessionDiagnosticsArray(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *nodeId, void *nodeContext,
                            UA_Boolean sourceTimestamp,
                            const UA_NumericRange *range, UA_DataValue *value) {
    /* Allocate the output array */
    UA_SessionDiagnosticsDataType *sd = (UA_SessionDiagnosticsDataType*)
        UA_Array_new(server->sessionCount,
                     &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE]);
    if(!sd)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    lockServer(server);

    /* Collect the statistics */
    size_t i = 0;
    session_list_entry *session;
    LIST_FOREACH(session, &server->sessions, pointers) {
        setSessionDiagnostics(&session->session, &sd[i]);
        i++;
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, server->sessionCount,
                        &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE]);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

static void
setSessionSecurityDiagnostics(UA_Session *session,
                              UA_SessionSecurityDiagnosticsDataType *sd) {
    UA_SessionSecurityDiagnosticsDataType_copy(&session->securityDiagnostics, sd);
    UA_NodeId_copy(&session->sessionId, &sd->sessionId);
    UA_String_copy(&session->clientUserIdOfSession, &sd->clientUserIdOfSession);
    UA_SecureChannel *channel = session->channel;
    if(channel) {
        UA_ByteString_copy(&channel->remoteCertificate, &sd->clientCertificate);
        UA_String_copy(&channel->securityPolicy->policyUri, &sd->securityPolicyUri);
        sd->securityMode = channel->securityMode;
        sd->encoding = UA_STRING_ALLOC("UA Binary"); /* The only one atm */
        sd->transportProtocol = UA_STRING_ALLOC("opc.tcp"); /* The only one atm */
    }
}

static UA_StatusCode
readSessionDiagnostics(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *nodeId, void *nodeContext,
                       UA_Boolean sourceTimestamp,
                       const UA_NumericRange *range, UA_DataValue *value) {
    lockServer(server);

    /* Get the Session */
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Read the BrowseName */
    UA_QualifiedName bn;
    UA_StatusCode res = readWithReadValue(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &bn);
    if(res != UA_STATUSCODE_GOOD) {
        unlockServer(server);
        return res;
    }

    union {
        UA_SessionDiagnosticsDataType sddt;
        UA_SessionSecurityDiagnosticsDataType ssddt;
    } data;
    void *content;
    UA_Boolean isArray = false;
    const UA_DataType *type = NULL;
    UA_Boolean securityDiagnostics = false;

    char memberName[128];
    size_t memberOffset;
    UA_Boolean found;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    if(equalBrowseName(&bn.name, "SubscriptionDiagnosticsArray")) {
        res = setSessionSubscriptionDiagnostics(server, session, value);
        goto cleanup;
    }
#endif

    if(equalBrowseName(&bn.name, "SessionDiagnostics")) {
        setSessionDiagnostics(session, &data.sddt);
        content = &data.sddt;
        type = &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE];
    } else if(equalBrowseName(&bn.name, "SessionSecurityDiagnostics")) {
        setSessionSecurityDiagnostics(session, &data.ssddt);
        securityDiagnostics = true;
        content = &data.ssddt;
        type = &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE];
    } else {
        /* Try to find the member in SessionDiagnosticsDataType and
         * SessionSecurityDiagnosticsDataType */
        memcpy(memberName, bn.name.data, bn.name.length);
        memberName[bn.name.length] = 0;
        found = UA_DataType_getStructMember(&UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE],
                                            memberName, &memberOffset, &type, &isArray);
        if(found) {
            setSessionDiagnostics(session, &data.sddt);
            content = (void*)(((uintptr_t)&data.sddt) + memberOffset);
        } else {
            const UA_DataType *dt = &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE];
            found = UA_DataType_getStructMember(dt, memberName, &memberOffset,
                                                &type, &isArray);
            if(!found) {
                res = UA_STATUSCODE_BADNOTIMPLEMENTED;
                goto cleanup;
            }
            setSessionSecurityDiagnostics(session, &data.ssddt);
            securityDiagnostics = true;
            content = (void*)(((uintptr_t)&data.ssddt) + memberOffset);
        }
    }

    if(!isArray) {
        res = UA_Variant_setScalarCopy(&value->value, content, type);
    } else {
        size_t len = *(size_t*)content;
        content = *(void**)((uintptr_t)content + sizeof(size_t));
        res = UA_Variant_setArrayCopy(&value->value, content, len, type);
    }
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        value->hasValue = true;

    if(securityDiagnostics)
        UA_SessionSecurityDiagnosticsDataType_clear(&data.ssddt);
    else
        UA_SessionDiagnosticsDataType_clear(&data.sddt);

 cleanup:
    UA_QualifiedName_clear(&bn);
    unlockServer(server);
    return res;
}

UA_StatusCode
readSessionSecurityDiagnostics(UA_Server *server,
                               const UA_NodeId *sessionId, void *sessionContext,
                               const UA_NodeId *nodeId, void *nodeContext,
                               UA_Boolean sourceTimestamp,
                               const UA_NumericRange *range, UA_DataValue *value) {
    /* Allocate the output array */
    UA_SessionSecurityDiagnosticsDataType *sd = (UA_SessionSecurityDiagnosticsDataType*)
        UA_Array_new(server->sessionCount,
                     &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE]);
    if(!sd)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    lockServer(server);

    /* Collect the statistics */
    size_t i = 0;
    session_list_entry *session;
    LIST_FOREACH(session, &server->sessions, pointers) {
        setSessionSecurityDiagnostics(&session->session, &sd[i]);
        i++;
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, server->sessionCount,
                        &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE]);

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

void
createSessionObject(UA_Server *server, UA_Session *session) {
    UA_ExpandedNodeId *children = NULL;
    size_t childrenSize = 0;
    UA_ReferenceTypeSet refTypes;
    UA_NodeId hasComponent = UA_NS0ID(HASCOMPONENT);
    UA_CallbackValueSource sessionDiagSource = {readSessionDiagnostics, NULL};

    /* Create an object for the session. Instantiates all the mandatory children. */
    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName.text = session->sessionName;
    UA_NodeId parentId = UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY);
    UA_NodeId refId = UA_NS0ID(HASCOMPONENT);
    UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, "");
    browseName.name = session->sessionName; /* shallow copy */
    UA_NodeId typeId = UA_NS0ID(SESSIONDIAGNOSTICSOBJECTTYPE);
    UA_StatusCode res = addNode(server, UA_NODECLASS_OBJECT, session->sessionId,
                                parentId, refId, browseName, typeId, &object_attr,
                                &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, NULL);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Recursively browse all children */
    res = referenceTypeIndices(server, &hasComponent, &refTypes, false);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    res = browseRecursive(server, 1, &session->sessionId,
                          UA_BROWSEDIRECTION_FORWARD, &refTypes,
                          UA_NODECLASS_VARIABLE, false, &childrenSize, &children);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Add the callback to all variables  */
    for(size_t i = 0; i < childrenSize; i++) {
        setVariableNode_callbackValueSource(server, children[i].nodeId, sessionDiagSource);
    }

 cleanup:
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Creating the session diagnostics object failed "
                               "with StatusCode %s", UA_StatusCode_name(res));
    }
    UA_Array_delete(children, childrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
}

/***************************/
/* Server-Wide Diagnostics */
/***************************/

UA_StatusCode
readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp,
                const UA_NumericRange *range, UA_DataValue *value) {
    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    if(sourceTimestamp) {
        UA_EventLoop *el = server->config.eventLoop;
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }

    UA_assert(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC);

    void *data = NULL;
    const UA_DataType *type = &UA_TYPES[UA_TYPES_UINT32]; /* Default */

    lockServer(server);

    switch(nodeId->identifier.numeric) {
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY:
        server->serverDiagnosticsSummary.currentSessionCount =
            server->activeSessionCount;
        data = &server->serverDiagnosticsSummary;
        type = &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE];
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SERVERVIEWCOUNT:
        data = &server->serverDiagnosticsSummary.serverViewCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT:
        data = &server->activeSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT:
        data = &server->serverDiagnosticsSummary.cumulatedSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDSESSIONCOUNT:
        data = &server->serverDiagnosticsSummary.securityRejectedSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDSESSIONCOUNT:
        data = &server->serverDiagnosticsSummary.rejectedSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONTIMEOUTCOUNT:
        data = &server->serverDiagnosticsSummary.sessionTimeoutCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONABORTCOUNT:
        data = &server->serverDiagnosticsSummary.sessionAbortCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSUBSCRIPTIONCOUNT:
        data = &server->serverDiagnosticsSummary.currentSubscriptionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSUBSCRIPTIONCOUNT:
        data = &server->serverDiagnosticsSummary.cumulatedSubscriptionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_PUBLISHINGINTERVALCOUNT:
        data = &server->serverDiagnosticsSummary.publishingIntervalCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDREQUESTSCOUNT:
        data = &server->serverDiagnosticsSummary.securityRejectedRequestsCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDREQUESTSCOUNT:
        data = &server->serverDiagnosticsSummary.rejectedRequestsCount;
        break;
    default:
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode res = UA_Variant_setScalarCopy(&value->value, data, type);
    if(res == UA_STATUSCODE_GOOD)
        value->hasValue = true;

    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_DIAGNOSTICS */

/**** amalgamated original file "/src/server/ua_server_ns0_gds.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_GDS_PUSHMANAGEMENT

#define UA_SHA1_LENGTH 20
#define CHECKACTIVESESSIONINTERVAL 10000 /* 10sec */

typedef struct UA_FileContext {
    LIST_ENTRY(UA_FileContext) listEntry;
    UA_ByteString file;
    /* Caches any data to be written using the Write method.
     * With a CloseAndUpdate, the data to be written is applied to the transaction. */
    UA_ByteString dataToWrite;
    UA_UInt32 fileHandle;
    UA_NodeId sessionId;
    UA_UInt64 currentPos;
    UA_Byte openFileMode;
} UA_FileContext;

typedef struct UA_FileInfo {
    UA_UInt16 openCount;
    UA_UtcTime lastUpdateTime;
    LIST_HEAD(, UA_FileContext)fileContext;
} UA_FileInfo;

typedef struct UA_FileInfoContext {
    struct UA_FileInfoContext *next;
    UA_NodeId certificateGroupId;
    UA_FileInfo fileInfo;
} UA_FileInfoContext;


static UA_StatusCode applyChangesToServer(UA_Server *server);

static UA_FileInfo*
getFileInfo(UA_GDSManager *gdsManager, UA_NodeId certificateGroupId) {
    UA_FileInfoContext *fileInfoContext = (UA_FileInfoContext*)gdsManager->fileInfoContext;
    while(fileInfoContext) {
        if(UA_NodeId_equal(&fileInfoContext->certificateGroupId, &certificateGroupId))
            return &fileInfoContext->fileInfo;
        fileInfoContext = fileInfoContext->next;
    }
    return NULL;
}


/********************/
/*   GDS Manager    */
/********************/

void
UA_GDSManager_clear(UA_GDSManager *gdsManager) {
    if(!gdsManager)
        return;
    gdsManager->checkSessionCallbackId = 0;
    UA_GDSTransaction_clear(&gdsManager->transaction);
    UA_FileInfoContext *fileInfoContext = (UA_FileInfoContext*)(gdsManager->fileInfoContext);

    /* free all fileInfoContexts */
    while(fileInfoContext) {
        UA_FileInfoContext *next = fileInfoContext->next;
        UA_FileInfo *fileInfo = &(fileInfoContext->fileInfo);
        UA_FileContext *fileContext = NULL;
        UA_FileContext *fileContextTmp = NULL;

        /* free all fileContexts in this fileInfoContext */
        LIST_FOREACH_SAFE(fileContext, &(fileInfo->fileContext), listEntry, fileContextTmp) {
            UA_ByteString_clear(&(fileContext->file));
            UA_ByteString_clear(&(fileContext->dataToWrite));
            LIST_REMOVE(fileContext, listEntry);
            UA_free(fileContext);
        }

        UA_free(fileInfoContext);
        fileInfoContext = next;
    }
}


static UA_StatusCode
createFileHandleId(UA_FileInfo *fileInfo, UA_UInt32 *fileHandle) {
    if(!fileInfo || !fileHandle)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_UInt32 id;
    UA_Boolean isFree = true;
    for(id = 1; id < UA_UINT32_MAX; id++) {
        UA_FileContext *fileContext = NULL;
        LIST_FOREACH(fileContext, &fileInfo->fileContext, listEntry) {
            if(fileContext->fileHandle == id){
                isFree = false;
                break;
            }
        }
        if(isFree) {
            *fileHandle = id;
            return UA_STATUSCODE_GOOD;
        }
        isFree = true;
    }
    return UA_STATUSCODE_BADINTERNALERROR;
}

static UA_FileContext*
getFileContext(UA_FileInfo *fileInfo, const UA_NodeId *sessionId, const UA_UInt32 fileHandle) {
    if(!fileInfo || !sessionId)
        return NULL;

    UA_FileContext *fileContext = NULL;
    LIST_FOREACH(fileContext, &fileInfo->fileContext, listEntry) {
        if(fileContext->fileHandle == fileHandle &&
           UA_NodeId_equal(&fileContext->sessionId, sessionId)){
            return fileContext;
        }
    }
    return NULL;
}

static UA_CertificateGroup*
getCertGroup(UA_Server *server, const UA_NodeId *objectId) {
    UA_NodeId defaultApplicationTrustList =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST);
    UA_NodeId defaultUserTokenTrustList =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST);
    UA_NodeId defaultApplicationGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    UA_NodeId defaultUserTokenGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);

    if(UA_NodeId_equal(objectId, &defaultApplicationGroup) ||
       UA_NodeId_equal(objectId, &defaultApplicationTrustList)) {
        return &server->config.secureChannelPKI;
    }
    if(UA_NodeId_equal(objectId, &defaultUserTokenGroup) ||
       UA_NodeId_equal(objectId, &defaultUserTokenTrustList)) {
        return &server->config.sessionPKI;
    }

    return NULL;
}

static UA_StatusCode
writeGDSNs0VariableArray(UA_Server *server, const UA_NodeId id, void *v,
                         size_t length, const UA_DataType *type) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setArray(&var, v, length, type);
    return writeValueAttribute(server, id, &var);
}

static UA_StatusCode
writeGDSNs0Variable(UA_Server *server, const UA_NodeId id,
                    void *v, const UA_DataType *type) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setScalar(&var, v, type);
    return writeValueAttribute(server, id, &var);
}

static UA_StatusCode
writeOpenCountVariable(UA_Server *server, UA_CertificateGroup *group) {
    UA_NodeId defaultApplicationGroup =
    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    UA_NodeId defaultUserTokenGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);

    UA_FileInfo *fileInfo = getFileInfo(&server->gdsManager, group->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(UA_NodeId_equal(&group->certificateGroupId, &defaultApplicationGroup)) {
        return writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_OPENCOUNT),
                           &fileInfo->openCount, &UA_TYPES[UA_TYPES_UINT16]);
    }
    if(UA_NodeId_equal(&group->certificateGroupId, &defaultUserTokenGroup)) {
        return writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_OPENCOUNT),
                           &fileInfo->openCount, &UA_TYPES[UA_TYPES_UINT16]);
    }

    return UA_STATUSCODE_BADINVALIDARGUMENT;
}

static UA_StatusCode
writeLastUpdateVariable(UA_Server *server, UA_CertificateGroup *group) {
    UA_NodeId defaultApplicationGroup =
    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    UA_NodeId defaultUserTokenGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);

    UA_FileInfo *fileInfo = getFileInfo(&server->gdsManager, group->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(UA_NodeId_equal(&group->certificateGroupId, &defaultApplicationGroup)) {
        return writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_LASTUPDATETIME),
                                  &fileInfo->lastUpdateTime, &UA_TYPES[UA_TYPES_UTCTIME]);
    }
    if(UA_NodeId_equal(&group->certificateGroupId, &defaultUserTokenGroup)) {
        return writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_LASTUPDATETIME),
                                  &fileInfo->lastUpdateTime, &UA_TYPES[UA_TYPES_UTCTIME]);
    }

    return UA_STATUSCODE_BADINVALIDARGUMENT;
}

/* This callback is triggered at regular intervals as long as a transaction is ongoing
 * or a client has a TrustList open for reading or writing.
 * If the session is no longer active, the current transaction is cancelled,
 * and all open file handles are closed. */
static void
checkSessionActive(UA_Server *server, void *data) {
    lockServer(server);
    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    UA_Boolean removingCallback = false;
    if(transaction->state != UA_GDSTRANSACTIONSTATE_FRESH) {
        UA_Boolean foundSession = false;
        session_list_entry *session;
        LIST_FOREACH(session, &server->sessions, pointers) {
            if(UA_NodeId_equal(&session->session.sessionId, &transaction->sessionId)) {
                foundSession = true;
                break;
            }
        }
        if(!foundSession) {
            UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "Session with an open transaction has ended. "
                "The transaction has been discarded.");
            UA_GDSTransaction_clear(transaction);
            removingCallback = true;
        }
    } else {
        removingCallback = true;
    }

    UA_FileInfoContext *fileInfoContext = (UA_FileInfoContext*)gdsManager->fileInfoContext;
    while(fileInfoContext) {
        UA_FileInfo fileInfo = fileInfoContext->fileInfo;

        if(fileInfo.openCount == 0) {
            fileInfoContext = fileInfoContext->next;
            continue;
        }

        removingCallback = false;

        UA_CertificateGroup *certGroup = getCertGroup(server, &fileInfoContext->certificateGroupId);
        if(!certGroup)
            continue;

        UA_FileContext *fileContext, *fileContextTmp;
        LIST_FOREACH_SAFE(fileContext, &fileInfo.fileContext, listEntry, fileContextTmp) {
            UA_Boolean foundSession = false;
            session_list_entry *session;
            LIST_FOREACH(session, &server->sessions, pointers) {
                if(UA_NodeId_equal(&session->session.sessionId, &fileContext->sessionId)) {
                    foundSession = true;
                    break;
                }
            }

            if(foundSession)
                continue;

            UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Session with an open trust list has ended. "
                    "All file handlers for the open trust lists have been closed.");

            LIST_REMOVE(fileContext, listEntry);
            fileInfoContext->fileInfo.openCount -= 1;

            UA_ByteString_clear(&fileContext->file);
            UA_ByteString_clear(&fileContext->dataToWrite);
            UA_free(fileContext);

            /* Updating OpenCount Variable in the information model */
            writeOpenCountVariable(server, certGroup);
        }

        fileInfoContext = fileInfoContext->next;
    }

    if(removingCallback) {
        removeCallback(server, gdsManager->checkSessionCallbackId);
        gdsManager->checkSessionCallbackId = 0;
    }
    unlockServer(server);
}

static UA_StatusCode
updateCertificate(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_NODEID]) || /*CertificateGroupId*/
       !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_NODEID]) || /*CertificateTypeId*/
       !UA_Variant_hasScalarType(&input[2], &UA_TYPES[UA_TYPES_BYTESTRING]) || /*Certificate*/
       !UA_Variant_hasArrayType(&input[3], &UA_TYPES[UA_TYPES_BYTESTRING]) || /*IssuerCertificates*/
       !UA_Variant_hasScalarType(&input[4], &UA_TYPES[UA_TYPES_STRING]) || /*PrivateKeyFormat*/
       !UA_Variant_hasScalarType(&input[5], &UA_TYPES[UA_TYPES_BYTESTRING])) /*PrivateKey*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_NodeId *certificateGroupId = (UA_NodeId *)input[0].data;
    UA_NodeId *certificateTypeId = (UA_NodeId *)input[1].data;
    UA_ByteString *certificate = (UA_ByteString *)input[2].data;
    /* TODO: Process issuer certificates */
    /* UA_ByteString *issuerCertificates = ((UA_ByteString *)input[3].data); */
    /* size_t issuerCertificatesSize = input[3].arrayLength; */
    UA_String *privateKeyFormat = (UA_String *)input[4].data;
    UA_ByteString *privateKey = (UA_ByteString *)input[5].data;

    /* The server currently only supports the DefaultApplicationGroup */
    UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    if(!UA_NodeId_equal(certificateGroupId, &defaultApplicationGroup))
        return UA_STATUSCODE_BADNOTSUPPORTED;

    /* The server currently only supports the following certificate type */
    UA_NodeId certTypRsaMin = UA_NODEID_NUMERIC(0, UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE);
    UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
    if(!UA_NodeId_equal(certificateTypeId, &certTypRsaSha256) && !UA_NodeId_equal(certificateTypeId, &certTypRsaMin))
        return UA_STATUSCODE_BADNOTSUPPORTED;

    /* Verify that the privateKey is in a supported format and
     * that it matches the specified certificate */
    if(privateKey && privateKey->length > 0) {
        const UA_String pemFormat = UA_STRING("PEM");
        const UA_String derFormat = UA_STRING("DER");
        if(!UA_String_equal(&pemFormat, privateKeyFormat) && !UA_String_equal(&derFormat, privateKeyFormat))
            return UA_STATUSCODE_BADNOTSUPPORTED;
        if(UA_CertificateUtils_checkKeyPair(certificate, privateKey) != UA_STATUSCODE_GOOD)
            return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    if(transaction->state == UA_GDSTRANSACTIONSTATE_FRESH) {
        retval = UA_GDSTransaction_init(transaction, server, *sessionId);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    if(gdsManager->checkSessionCallbackId == 0) {
        retval = addRepeatedCallback(server, (UA_ServerCallback)checkSessionActive, NULL,
                                     CHECKACTIVESESSIONINTERVAL, &gdsManager->checkSessionCallbackId);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    if(!UA_NodeId_equal(&transaction->sessionId, sessionId))
        return UA_STATUSCODE_BADTRANSACTIONPENDING;

    retval = UA_GDSTransaction_addCertificateInfo(transaction, *certificateGroupId,
                                                  *certificateTypeId, certificate, privateKey);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Output arg, indicates that the ApplyChanges Method shall be called before the new Certificate will be used. */
    UA_Boolean applyChangesRequired = true;
    UA_Variant_setScalarCopy(output, &applyChangesRequired, &UA_TYPES[UA_TYPES_BOOLEAN]);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
createSigningRequest(UA_Server *server,
                     const UA_NodeId *sessionId, void *sessionHandle,
                     const UA_NodeId *methodId, void *methodContext,
                     const UA_NodeId *objectId, void *objectContext,
                     size_t inputSize, const UA_Variant *input,
                     size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_NODEID]) || /*CertificateGroupId*/
       !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_NODEID]) || /*CertificateTypeId*/
       !UA_Variant_hasScalarType(&input[2], &UA_TYPES[UA_TYPES_STRING]) || /*SubjectName*/
       !UA_Variant_hasScalarType(&input[3], &UA_TYPES[UA_TYPES_BOOLEAN]) || /*RegeneratePrivateKey*/
       !UA_Variant_hasScalarType(&input[4], &UA_TYPES[UA_TYPES_BYTESTRING]))  /*Nonce*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_NodeId *certificateGroupId = (UA_NodeId *)input[0].data;
    UA_NodeId *certificateTypeId = (UA_NodeId *)input[1].data;
    UA_String *subjectName = (UA_String *)input[2].data;
    UA_Boolean *regenerateKey = ((UA_Boolean *)input[3].data);
    UA_ByteString *nonce = (UA_ByteString *)input[4].data;
    UA_ByteString *csr = UA_ByteString_new();

    UA_StatusCode retval =
        UA_Server_createSigningRequest(server, *certificateGroupId,
                                       *certificateTypeId, subjectName,
                                       regenerateKey, nonce, csr);

    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_delete(csr);
        return retval;
    }

    /* Output arg, the PKCS #10 DER encoded Certificate Request (CSR) */
    UA_Variant_setScalarCopy(output, csr, &UA_TYPES[UA_TYPES_BYTESTRING]);
    UA_ByteString_delete(csr);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
getRejectedList(UA_Server *server,
                const UA_NodeId *sessionId, void *sessionHandle,
                const UA_NodeId *methodId, void *methodContext,
                const UA_NodeId *objectId, void *objectContext,
                size_t inputSize, const UA_Variant *input,
                size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    size_t rejectedListSize = 0;
    UA_CertificateGroup certGroup = server->config.secureChannelPKI;

    /* DefaultApplicationGroup */
    UA_ByteString *rejectedListSecureChannel = NULL;
    size_t rejectedListSecureChannelSize = 0;
    certGroup.getRejectedList(&certGroup, &rejectedListSecureChannel, &rejectedListSecureChannelSize);
    rejectedListSize += rejectedListSecureChannelSize;

    /* DefaultUserTokenGroup */
    certGroup = server->config.sessionPKI;
    UA_ByteString *rejectedListSession = NULL;
    size_t rejectedListSessionSize = 0;
    certGroup.getRejectedList(&certGroup, &rejectedListSession, &rejectedListSessionSize);
    rejectedListSize += rejectedListSessionSize;

    if(rejectedListSize == 0) {
        UA_Variant_setArray(&output[0], NULL, rejectedListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        return UA_STATUSCODE_GOOD;
    }

    UA_ByteString *rejectedList = (UA_ByteString*)UA_Array_new(rejectedListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
    if(!rejectedList) {
        UA_Array_delete(rejectedListSecureChannel, rejectedListSecureChannelSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        UA_Array_delete(rejectedListSession, rejectedListSessionSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    memcpy(rejectedList, rejectedListSecureChannel, rejectedListSecureChannelSize * sizeof(UA_ByteString));
    memcpy(rejectedList + rejectedListSecureChannelSize, rejectedListSession, rejectedListSessionSize * sizeof(UA_ByteString));

    UA_Variant_setArrayCopy(&output[0], rejectedList,
                        rejectedListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);

    UA_Array_delete(rejectedListSecureChannel, rejectedListSecureChannelSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
    UA_Array_delete(rejectedListSession, rejectedListSessionSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
    UA_free(rejectedList);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addCertificate(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionHandle,
               const UA_NodeId *methodId, void *methodContext,
               const UA_NodeId *objectId, void *objectContext,
               size_t inputSize, const UA_Variant *input,
               size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_BYTESTRING]) || /*Certificate*/
       !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_BOOLEAN])) /*IsTrustedCertificate*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_ByteString certificate = *(UA_ByteString *)input[0].data;
    UA_Boolean isTrustedCertificate = *(UA_Boolean *)input[1].data;

    if(!isTrustedCertificate || certificate.length == 0)
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    UA_GDSManager *gdsManager = &server->gdsManager;
    if(gdsManager->transaction.state != UA_GDSTRANSACTIONSTATE_FRESH)
        return UA_STATUSCODE_BADTRANSACTIONPENDING;

    /* CA certificates cannot be added using this method because it does not support adding CRLs */
    if(UA_CertificateUtils_checkCA(&certificate) == UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
            "The certificate could not be added because it is a CA certificate. "
            "CA certificates must be added using the FileType methods.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* This Method cannot be called if the containing TrustList Object is open */
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(fileInfo->openCount > 0)
        return UA_STATUSCODE_BADINVALIDSTATE;

    UA_TrustListDataType trustList;
    memset(&trustList, 0, sizeof(UA_TrustListDataType));
    UA_ByteString certificates[1];
    certificates[0] = certificate;

    trustList.specifiedLists = UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES;
    trustList.trustedCertificates = certificates;
    trustList.trustedCertificatesSize = 1;

    UA_StatusCode retval = certGroup->addToTrustList(certGroup, &trustList);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Updating LastUpdateTime Variable in the information model */
    fileInfo->lastUpdateTime = UA_DateTime_now();
    writeLastUpdateVariable(server, certGroup);

    return retval;
}

static UA_StatusCode
removeCertificate(UA_Server *server,
                const UA_NodeId *sessionId, void *sessionHandle,
                const UA_NodeId *methodId, void *methodContext,
                const UA_NodeId *objectId, void *objectContext,
                size_t inputSize, const UA_Variant *input,
                size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_STRING]) || /*Thumbprint*/
       !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_BOOLEAN])) /*IsTrustedCertificate*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_String thumbprint = *(UA_String *)input[0].data;
    UA_Boolean isTrustedCertificate = *(UA_Boolean *)input[1].data;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    if(transaction->state != UA_GDSTRANSACTIONSTATE_FRESH)
        return UA_STATUSCODE_BADTRANSACTIONPENDING;

    /* When a certificate is removed, a transaction is created which is then executed directly.
     * No apply cahnges is required */
    UA_StatusCode retval = UA_GDSTransaction_init(transaction, server, *sessionId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* This Method cannot be called if the containing TrustList Object is open */
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(fileInfo->openCount > 0)
        return UA_STATUSCODE_BADINVALIDSTATE;

    UA_TrustListDataType trustList;
    memset(&trustList, 0, sizeof(UA_TrustListDataType));
    trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;

    UA_ByteString *certificates;
    size_t certificatesSize = 0;
    certGroup->getTrustList(certGroup, &trustList);

    if(isTrustedCertificate) {
        certificates = trustList.trustedCertificates;
        certificatesSize = trustList.trustedCertificatesSize;
    } else {
        certificates = trustList.issuerCertificates;
        certificatesSize = trustList.issuerCertificatesSize;
    }

    UA_TrustListDataType list;
    memset(&list, 0, sizeof(UA_TrustListDataType));

    UA_ByteString *crls = NULL;
    size_t crlsSize = 0;

    UA_ByteString certificate = UA_BYTESTRING_NULL;

    UA_String thumbpr = UA_STRING_NULL;
    thumbpr.length = (UA_SHA1_LENGTH * 2);
    thumbpr.data = (UA_Byte*)UA_malloc(sizeof(UA_Byte)*thumbpr.length);

    for(size_t i = 0; i < certificatesSize; i++) {
        UA_CertificateUtils_getThumbprint( &certificates[i], &thumbpr);
        /* Compare thumbprint */
        if(!UA_String_equal_ignorecase(&thumbprint, &thumbpr))
            continue;

        certificate = certificates[i];
        retval = certGroup->getCertificateCrls(certGroup, &certificate, isTrustedCertificate,
                                               &crls, &crlsSize);
        /* Tolerate "Bad_NoMatch" to support removing CA certificates that do
         * not have an associated CRL. */
        if((retval != UA_STATUSCODE_GOOD) && (retval != UA_STATUSCODE_BADNOMATCH)) {
            goto cleanup;
        }

        if(isTrustedCertificate) {
            list.specifiedLists = UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES | UA_TRUSTLISTMASKS_TRUSTEDCRLS;
            list.trustedCertificates = &certificate;
            list.trustedCertificatesSize = 1;
            list.trustedCrls = crls;
            list.trustedCrlsSize = crlsSize;
        } else {
            list.specifiedLists = UA_TRUSTLISTMASKS_ISSUERCERTIFICATES | UA_TRUSTLISTMASKS_ISSUERCRLS;
            list.issuerCertificates = &certificate;
            list.issuerCertificatesSize = 1;
            list.issuerCrls = crls;
            list.issuerCrlsSize = crlsSize;
        }
        break;
    }

    UA_CertificateGroup *transactionCertGroup =
        UA_GDSTransaction_getCertificateGroup(transaction, certGroup);
    if(!transactionCertGroup) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(list.specifiedLists != UA_TRUSTLISTMASKS_NONE) {
        retval = transactionCertGroup->removeFromTrustList(transactionCertGroup, &list);
        if(retval != UA_STATUSCODE_GOOD) {
            goto cleanup;
        }
    } else {
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER, "The certificate to remove was not found");
        retval = UA_STATUSCODE_BADINVALIDARGUMENT;
        goto cleanup;
    }

    retval = applyChangesToServer(server);

cleanup:
    UA_String_clear(&thumbpr);
    UA_TrustListDataType_clear(&trustList);
    UA_Array_delete(crls, crlsSize, &UA_TYPES[UA_TYPES_BYTESTRING]);

    return retval;
}

static UA_StatusCode
openTrustList(UA_Server *server,
              const UA_NodeId *sessionId, void *sessionHandle,
              const UA_NodeId *methodId, void *methodContext,
              const UA_NodeId *objectId, void *objectContext,
              size_t inputSize, const UA_Variant *input,
              size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_BYTE]))/*FileMode*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_Byte fileOpenMode = *(UA_Byte*)input[0].data;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    /* Cannot be opened when a transaction is running */
    if(transaction->state == UA_GDSTRANSACTIONSTATE_PENDING)
        return UA_STATUSCODE_BADTRANSACTIONPENDING;

    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Check that the list can be opened in the specified mode */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(fileOpenMode == (UA_OPENFILEMODE_WRITE | UA_OPENFILEMODE_ERASEEXISTING)) {
        if(fileInfo->openCount != 0)
            return UA_STATUSCODE_BADNOTWRITABLE;
    } else if(fileOpenMode == UA_OPENFILEMODE_READ) {
        /* Nothing to check.
         * If the list is already open for writing,
         * the previous check for a current transaction will fail. */
    } else {
        return UA_STATUSCODE_BADINVALIDSTATE;
    }

    /* If the list is opened for writing, a transaction must be created */
    if(fileOpenMode == (UA_OPENFILEMODE_WRITE | UA_OPENFILEMODE_ERASEEXISTING)) {
        retval = UA_GDSTransaction_init(transaction, server, *sessionId);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    if(gdsManager->checkSessionCallbackId == 0) {
        retval = addRepeatedCallback(server, (UA_ServerCallback)checkSessionActive, NULL,
                                     CHECKACTIVESESSIONINTERVAL, &gdsManager->checkSessionCallbackId);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    UA_TrustListDataType trustList;
    memset(&trustList, 0, sizeof(UA_TrustListDataType));
    trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;
    certGroup->getTrustList(certGroup, &trustList);

    UA_ByteString encTrustList = UA_BYTESTRING_NULL;
    retval = UA_encodeBinary(&trustList, &UA_TYPES[UA_TYPES_TRUSTLISTDATATYPE], &encTrustList, NULL);
    UA_TrustListDataType_clear(&trustList);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&encTrustList);
        return retval;
    }

    UA_FileContext *fileContext = (UA_FileContext*)UA_calloc(1, sizeof(UA_FileContext));
    fileContext->file = encTrustList;
    fileContext->sessionId = *sessionId;
    fileContext->openFileMode = fileOpenMode;
    fileContext->currentPos = 0;
    fileContext->dataToWrite = UA_BYTESTRING_NULL;
    retval = createFileHandleId(fileInfo, &fileContext->fileHandle);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&fileContext->file);
        UA_free(fileContext);
        return retval;
    }

    fileInfo->openCount += 1;
    UA_Variant_setScalarCopy(output, &fileContext->fileHandle, &UA_TYPES[UA_TYPES_UINT32]);

    /* Updating OpenCount Variable in the information model */
    writeOpenCountVariable(server, certGroup);

    LIST_INSERT_HEAD(&fileInfo->fileContext, fileContext, listEntry);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
openTrustListWithMask(UA_Server *server,
                      const UA_NodeId *sessionId, void *sessionHandle,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext,
                      size_t inputSize, const UA_Variant *input,
                      size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_UINT32])) /*Mask*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_UInt32 mask = *(UA_UInt32*)input[0].data;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    if(gdsManager->transaction.state == UA_GDSTRANSACTIONSTATE_PENDING)
        return UA_STATUSCODE_BADTRANSACTIONPENDING;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(gdsManager->checkSessionCallbackId == 0) {
        retval = addRepeatedCallback(server, (UA_ServerCallback)checkSessionActive, NULL,
                                     CHECKACTIVESESSIONINTERVAL, &gdsManager->checkSessionCallbackId);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    UA_TrustListDataType trustList;
    memset(&trustList, 0, sizeof(UA_TrustListDataType));
    trustList.specifiedLists = mask;
    certGroup->getTrustList(certGroup, &trustList);

    UA_ByteString encTrustList = UA_BYTESTRING_NULL;
    retval = UA_encodeBinary(&trustList, &UA_TYPES[UA_TYPES_TRUSTLISTDATATYPE], &encTrustList, NULL);
    UA_TrustListDataType_clear(&trustList);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&encTrustList);
        return retval;
    }

    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_FileContext *fileContext = (UA_FileContext*)UA_calloc(1, sizeof(UA_FileContext));
    fileContext->file = encTrustList;
    fileContext->sessionId = *sessionId;
    fileContext->openFileMode = UA_OPENFILEMODE_READ;
    fileContext->currentPos = 0;
    fileContext->dataToWrite = UA_BYTESTRING_NULL;
    retval = createFileHandleId(fileInfo, &fileContext->fileHandle);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&fileContext->file);
        UA_free(fileContext);
        return retval;
    }

    fileInfo->openCount += 1;
    UA_Variant_setScalarCopy(output, &fileContext->fileHandle, &UA_TYPES[UA_TYPES_UINT32]);

    /* Updating OpenCount Variable in the information model */
    writeOpenCountVariable(server, certGroup);

    LIST_INSERT_HEAD(&fileInfo->fileContext, fileContext, listEntry);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readTrustList(UA_Server *server,
              const UA_NodeId *sessionId, void *sessionHandle,
              const UA_NodeId *methodId, void *methodContext,
              const UA_NodeId *objectId, void *objectContext,
              size_t inputSize, const UA_Variant *input,
              size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_UINT32]) || /*FileHandle*/
       !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_INT32])) /*Length*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_UInt32 fileHandle = *(UA_UInt32*)input[0].data;
    UA_Int32 length = *(UA_Int32*)input[1].data;
    if(length < 0)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_FileContext *fileContext = getFileContext(fileInfo, sessionId, fileHandle);
    if(!fileContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(fileContext->openFileMode != UA_OPENFILEMODE_READ)
        return UA_STATUSCODE_BADINVALIDSTATE;

    /* check boundaries */
    if((size_t)length >= fileContext->file.length)
        length = (UA_Int32)fileContext->file.length;

    if((size_t)length >= (fileContext->file.length - fileContext->currentPos))
        length = (UA_Int32)(fileContext->file.length - fileContext->currentPos);

    UA_ByteString readBuffer = UA_BYTESTRING_NULL;
    if(length > 0) {
        readBuffer.length = (size_t)length;
        readBuffer.data = fileContext->file.data+fileContext->currentPos;
        fileContext->currentPos += (UA_UInt64)length;
    }

    UA_Variant_setScalarCopy(output, &readBuffer, &UA_TYPES[UA_TYPES_BYTESTRING]);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeTrustList(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionHandle,
               const UA_NodeId *methodId, void *methodContext,
               const UA_NodeId *objectId, void *objectContext,
               size_t inputSize, const UA_Variant *input,
               size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_UINT32]) || /*FileHandle*/
       !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_BYTESTRING])) /*Data*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_UInt32 fileHandle = *(UA_UInt32*)input[0].data;
    UA_ByteString data = *(UA_ByteString*)input[1].data;

    if(data.length == 0)
        return UA_STATUSCODE_GOOD;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_FileContext *fileContext = getFileContext(fileInfo, sessionId, fileHandle);
    if(!fileContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(fileContext->openFileMode != (UA_OPENFILEMODE_WRITE | UA_OPENFILEMODE_ERASEEXISTING))
        return UA_STATUSCODE_BADINVALIDSTATE;

    /* abort when TrustList size would exceed the maximum allowed value (0 = unlimited) */
    if(server->config.maxTrustListSize != 0 &&
       (fileContext->dataToWrite.length + data.length) > server->config.maxTrustListSize) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Write on trust list exceeds limit");
        return UA_STATUSCODE_BADREQUESTTOOLARGE;
    }

    UA_ByteString dataToWrite = UA_BYTESTRING_NULL;
    UA_StatusCode retval = UA_ByteString_allocBuffer(&dataToWrite, fileContext->dataToWrite.length + data.length);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(fileContext->dataToWrite.length)
        memcpy(dataToWrite.data, fileContext->dataToWrite.data, fileContext->dataToWrite.length);
    memcpy(dataToWrite.data + fileContext->dataToWrite.length, data.data, data.length);

    UA_ByteString_clear(&fileContext->dataToWrite);
    fileContext->dataToWrite = dataToWrite;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
closeTrustList(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionHandle,
               const UA_NodeId *methodId, void *methodContext,
               const UA_NodeId *objectId, void *objectContext,
               size_t inputSize, const UA_Variant *input,
               size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_UINT32])) /*FileHandle*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_UInt32 fileHandle = *(UA_UInt32*)input[0].data;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_FileContext *fileContext = getFileContext(fileInfo, sessionId, fileHandle);
    if(!fileContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* If a close is called, a current transaction is cancelled.
     * If the list was opened in read mode, there are no changes to discard. */
    if(fileContext->openFileMode == (UA_OPENFILEMODE_WRITE | UA_OPENFILEMODE_ERASEEXISTING)) {
        UA_GDSTransaction_clear(transaction);
    }

    LIST_REMOVE(fileContext, listEntry);
    fileInfo->openCount -= 1;

    UA_ByteString_clear(&fileContext->file);
    UA_ByteString_clear(&fileContext->dataToWrite);
    UA_free(fileContext);

    /* Updating OpenCount Variable in the information model */
    writeOpenCountVariable(server, certGroup);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
closeAndUpdateTrustList(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionHandle,
               const UA_NodeId *methodId, void *methodContext,
               const UA_NodeId *objectId, void *objectContext,
               size_t inputSize, const UA_Variant *input,
               size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_UINT32])) /*FileHandle*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_UInt32 fileHandle = *(UA_UInt32*)input[0].data;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_FileContext *fileContext = getFileContext(fileInfo, sessionId, fileHandle);
    if(!fileContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(fileContext->openFileMode != (UA_OPENFILEMODE_WRITE | UA_OPENFILEMODE_ERASEEXISTING))
        return UA_STATUSCODE_BADINVALIDSTATE;

    UA_CertificateGroup *transactionCertGroup =
        UA_GDSTransaction_getCertificateGroup(transaction, certGroup);
    if(!transactionCertGroup)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_TrustListDataType trustList;
    UA_StatusCode retval =
        UA_decodeBinary(&fileContext->dataToWrite, &trustList, &UA_TYPES[UA_TYPES_TRUSTLISTDATATYPE], NULL);

    if(retval != UA_STATUSCODE_GOOD) {
        UA_TrustListDataType_clear(&trustList);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    retval = transactionCertGroup->setTrustList(transactionCertGroup, &trustList);
    UA_TrustListDataType_clear(&trustList);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    LIST_REMOVE(fileContext, listEntry);
    fileInfo->openCount -= 1;

    UA_ByteString_clear(&fileContext->file);
    UA_ByteString_clear(&fileContext->dataToWrite);
    UA_free(fileContext);

    /* Updating OpenCount Variable in the information model */
    writeOpenCountVariable(server, certGroup);

    /* Output arg, indicates that the ApplyChanges Method shall be called before the new trust list will be used. */
    UA_Boolean applyChangesRequired = true;
    UA_Variant_setScalarCopy(output, &applyChangesRequired, &UA_TYPES[UA_TYPES_BOOLEAN]);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
getPositionTrustList(UA_Server *server,
                     const UA_NodeId *sessionId, void *sessionHandle,
                     const UA_NodeId *methodId, void *methodContext,
                     const UA_NodeId *objectId, void *objectContext,
                     size_t inputSize, const UA_Variant *input,
                     size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_UINT32])) /*FileHandle*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_UInt32 fileHandle = *(UA_UInt32*)input[0].data;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_FileContext *fileContext = getFileContext(fileInfo, sessionId, fileHandle);
    if(!fileContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_Variant_setScalarCopy(output, &fileContext->currentPos, &UA_TYPES[UA_TYPES_UINT64]);
}

static UA_StatusCode
setPositionTrustList(UA_Server *server,
                     const UA_NodeId *sessionId, void *sessionHandle,
                     const UA_NodeId *methodId, void *methodContext,
                     const UA_NodeId *objectId, void *objectContext,
                     size_t inputSize, const UA_Variant *input,
                     size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    /*check for input types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_UINT32]) || /*FileHandle*/
       !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_UINT64])) /*Position*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_UInt32 fileHandle = *(UA_UInt32*)input[0].data;
    UA_UInt64 position = *(UA_UInt32*)input[1].data;

    UA_CertificateGroup *certGroup = getCertGroup(server, objectId);
    if(!certGroup)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
    if(!fileInfo)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_FileContext *fileContext = getFileContext(fileInfo, sessionId, fileHandle);
    if(!fileContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(fileContext->file.length < position) {
        fileContext->currentPos = fileContext->file.length;
    } else {
        fileContext->currentPos = position;
    }

    return UA_STATUSCODE_GOOD;
}

typedef enum UA_GDSTransactionChanges {
    UA_GDSTRANSACTIONCHANGES_NOTHING = 0,
    UA_GDSTRANSACTIONCHANGES_TRUSTLIST,
    UA_GDSTRANSACTIONCHANGES_CERTIFICATE,
    UA_GDSTRANSACTIONCHANGES_BOTH,
} UA_GDSTransactionChanges;

static void
secureChannel_delayedClose(void *application, void *context) {
    UA_Server *server = (UA_Server*)context;
    UA_GDSTransactionChanges *changes = (UA_GDSTransactionChanges*)application;

    if(*changes == UA_GDSTRANSACTIONCHANGES_NOTHING)
        goto cleanup;

    if(*changes == UA_GDSTRANSACTIONCHANGES_BOTH ||
       *changes == UA_GDSTRANSACTIONCHANGES_CERTIFICATE ) {
        UA_SecureChannel *channel;
        TAILQ_FOREACH(channel, &server->channels, serverEntry) {
            if(channel->state == UA_SECURECHANNELSTATE_CLOSED || channel->state == UA_SECURECHANNELSTATE_CLOSING)
                continue;
            UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
        }
        goto cleanup;
    }

    UA_CertificateGroup certGroup = server->config.secureChannelPKI;
    UA_SecureChannel *channel;
    TAILQ_FOREACH(channel, &server->channels, serverEntry) {
        if(channel->state == UA_SECURECHANNELSTATE_CLOSED || channel->state == UA_SECURECHANNELSTATE_CLOSING)
            continue;
        if(certGroup.verifyCertificate(&certGroup, &channel->remoteCertificate) != UA_STATUSCODE_GOOD)
            UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
    }

cleanup:
    UA_free(changes);
    UA_GDSTransaction_clear(&server->gdsManager.transaction);
}

static UA_StatusCode
applyChangesToServer(UA_Server *server) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    UA_GDSTransactionChanges *changes = (UA_GDSTransactionChanges*)UA_calloc(1, sizeof(UA_GDSTransactionChanges));

    /* Apply Trust list changes */
    for(size_t i = 0; i < transaction->certGroupSize; i++) {
        *changes = UA_GDSTRANSACTIONCHANGES_TRUSTLIST;
        UA_CertificateGroup transactionCertGroup = transaction->certGroups[i];
        UA_TrustListDataType trustList;
        UA_TrustListDataType_init(&trustList);
        trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;
        transactionCertGroup.getTrustList(&transactionCertGroup, &trustList);

        UA_CertificateGroup *certGroup = getCertGroup(server, &transactionCertGroup.certificateGroupId);
        if(!certGroup) {
            UA_TrustListDataType_clear(&trustList);
            goto cleanup;
        }
        retval = certGroup->setTrustList(certGroup, &trustList);
        UA_TrustListDataType_clear(&trustList);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;

        UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
        if(!fileInfo) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }

        /* Updating LastUpdateTime Variable in the information model */
        fileInfo->lastUpdateTime = UA_DateTime_now();
        writeLastUpdateVariable(server, certGroup);
    }

    /* Apply Server certificate changes */
    for(size_t i = 0; i < transaction->certificateInfosSize; i++) {
        if(*changes != UA_GDSTRANSACTIONCHANGES_NOTHING) {
            *changes = UA_GDSTRANSACTIONCHANGES_BOTH;
        } else {
            *changes = UA_GDSTRANSACTIONCHANGES_CERTIFICATE;
        }
        UA_GDSCertificateInfo certInfo = transaction->certificateInfos[i];
        UA_NodeId certTypeId = certInfo.certificateType;
        UA_ByteString certificate = certInfo.certificate;
        UA_ByteString privateKey = certInfo.privateKey;

        for(size_t j = 0; j < server->config.endpointsSize; j++) {
            UA_EndpointDescription *ed = &server->config.endpoints[j];
            UA_SecurityPolicy *sp = getSecurityPolicyByUri(server,
                                &server->config.endpoints[j].securityPolicyUri);
            if(!sp) {
                retval = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }

            if(!UA_NodeId_equal(&sp->certificateTypeId, &certTypeId))
                continue;

            retval = sp->updateCertificate(sp, certificate, privateKey);
            if(retval != UA_STATUSCODE_GOOD)
                goto cleanup;

            UA_ByteString_clear(&ed->serverCertificate);
            retval = UA_ByteString_copy(&certificate, &ed->serverCertificate);
            if(retval != UA_STATUSCODE_GOOD)
                goto cleanup;
        }
    }

    /* Add to the delayed callback list. Will be cleaned up in the next iteration. */
    UA_DelayedCallback *dc = &transaction->dc;
    dc->callback = secureChannel_delayedClose;
    dc->application = changes;
    dc->context = server;

    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, dc);

    return UA_STATUSCODE_GOOD;

cleanup:
    UA_GDSTransaction_clear(transaction);
    UA_free(changes);

    return retval;
}

static UA_StatusCode
applyChanges(UA_Server *server,
             const UA_NodeId *sessionId, void *sessionHandle,
             const UA_NodeId *methodId, void *methodContext,
             const UA_NodeId *objectId, void *objectContext,
             size_t inputSize, const UA_Variant *input,
             size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_GDSManager *gdsManager = &server->gdsManager;
    UA_GDSTransaction *transaction = &gdsManager->transaction;
    if(transaction->state == UA_GDSTRANSACTIONSTATE_FRESH)
        return UA_STATUSCODE_BADNOTHINGTODO;

    if(!UA_NodeId_equal(&transaction->sessionId, sessionId))
        return UA_STATUSCODE_BADUSERACCESSDENIED;

    /* Check if a TrustList is still open */
    for(size_t i = 0; i < transaction->certGroupSize; i++) {
        UA_CertificateGroup *certGroup = &transaction->certGroups[i];
        UA_FileInfo *fileInfo = getFileInfo(gdsManager, certGroup->certificateGroupId);
        if(!fileInfo)
            return UA_STATUSCODE_BADINTERNALERROR;
        if(fileInfo->openCount > 0)
            return UA_STATUSCODE_BADINVALIDSTATE;
    }

    return applyChangesToServer(server);
}

static UA_StatusCode
createFileInfoContexts(UA_Server *server) {
    /* The server currently only supports the DefaultApplicationGroup and UserTokenGroup */
    UA_UtcTime lastUpdateTime = UA_DateTime_now();

    UA_FileInfoContext *fileInfoContext = (UA_FileInfoContext*)UA_calloc(1, sizeof(UA_FileInfoContext));
    if(!fileInfoContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    fileInfoContext->next = (UA_FileInfoContext*)UA_calloc(1, sizeof(UA_FileInfoContext));
    if(!fileInfoContext->next) {
        UA_free(fileInfoContext);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    fileInfoContext->certificateGroupId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    LIST_INIT(&fileInfoContext->fileInfo.fileContext);
    fileInfoContext->fileInfo.lastUpdateTime = lastUpdateTime;

    fileInfoContext->next->certificateGroupId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
    LIST_INIT(&fileInfoContext->next->fileInfo.fileContext);
    fileInfoContext->next->fileInfo.lastUpdateTime = lastUpdateTime;

    server->gdsManager.fileInfoContext = fileInfoContext;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeGroupVariables(UA_Server *server) {
    UA_NodeId certificateTypes[2] = {UA_NODEID_NUMERIC(0, UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE),
                                     UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE)};
    size_t certificateTypesSize = 2;

    UA_String supportedPrivateKeyFormats[2] = {UA_STRING("PEM"),
                                               UA_STRING("DER")};
    size_t supportedPrivateKeyFormatsSize = 2;

    UA_UInt32  maxTrustListSize = 0;

    /* Set variables */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    retval |= writeGDSNs0VariableArray(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_SUPPORTEDPRIVATEKEYFORMATS),
                                       supportedPrivateKeyFormats, supportedPrivateKeyFormatsSize,
                                       &UA_TYPES[UA_TYPES_STRING]);

    retval |= writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_MAXTRUSTLISTSIZE),
                                  &maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);

    retval |= writeGDSNs0VariableArray(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_CERTIFICATETYPES),
                                       certificateTypes, certificateTypesSize,
                                       &UA_TYPES[UA_TYPES_NODEID]);

    /* DefaultApplicationGroup */
    UA_FileInfo *fileInfoApplicationGroup = getFileInfo(&server->gdsManager, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP));
    if(!fileInfoApplicationGroup)
        return UA_STATUSCODE_BADINTERNALERROR;

    retval |= writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_OPENCOUNT),
                                  &fileInfoApplicationGroup->openCount, &UA_TYPES[UA_TYPES_UINT16]);
    retval |= writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_LASTUPDATETIME),
                                  &fileInfoApplicationGroup->lastUpdateTime, &UA_TYPES[UA_TYPES_UTCTIME]);

    /* DefaultUserTokenGroup */
    UA_FileInfo *fileInfoUserTokenGroup = getFileInfo(&server->gdsManager, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP));
    if(!fileInfoUserTokenGroup)
        return UA_STATUSCODE_BADINTERNALERROR;

    retval |= writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_OPENCOUNT),
                                  &fileInfoUserTokenGroup->openCount, &UA_TYPES[UA_TYPES_UINT16]);
    retval |= writeGDSNs0Variable(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_LASTUPDATETIME),
                                  &fileInfoUserTokenGroup->lastUpdateTime, &UA_TYPES[UA_TYPES_UTCTIME]);

    return retval;
}

static UA_StatusCode
openFile(UA_Server *server,
         const UA_NodeId *sessionId, void *sessionHandle,
         const UA_NodeId *methodId, void *methodContext,
         const UA_NodeId *objectId, void *objectContext,
         size_t inputSize, const UA_Variant *input,
         size_t outputSize, UA_Variant *output) {

    const UA_Node *object = UA_NODESTORE_GET(server, objectId);
    if(!object)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    const UA_Node *objectType =
        getNodeType(server, &object->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);

    UA_NodeId trustListType = UA_NODEID_NUMERIC(0, UA_NS0ID_TRUSTLISTTYPE);
    UA_StatusCode retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
    if(UA_NodeId_equal(&objectType->head.nodeId, &trustListType)) {
        retval = openTrustList(server, sessionId, sessionHandle, methodId, methodContext,
                               objectId, objectContext, inputSize, input, outputSize, output);
    }

    UA_NODESTORE_RELEASE(server, object);
    UA_NODESTORE_RELEASE(server, objectType);

    if(retval != UA_STATUSCODE_BADNOTIMPLEMENTED)
        return retval;

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "File type functions are currently only supported for TrustList types");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static UA_StatusCode
readFile(UA_Server *server,
         const UA_NodeId *sessionId, void *sessionHandle,
         const UA_NodeId *methodId, void *methodContext,
         const UA_NodeId *objectId, void *objectContext,
         size_t inputSize, const UA_Variant *input,
         size_t outputSize, UA_Variant *output) {

    const UA_Node *object = UA_NODESTORE_GET(server, objectId);
    if(!object)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    const UA_Node *objectType =
        getNodeType(server, &object->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);

    UA_NodeId trustListType = UA_NODEID_NUMERIC(0, UA_NS0ID_TRUSTLISTTYPE);
    UA_StatusCode retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
    if(UA_NodeId_equal(&objectType->head.nodeId, &trustListType)) {
        retval =  readTrustList(server, sessionId, sessionHandle, methodId, methodContext,
                                objectId, objectContext, inputSize, input, outputSize, output);
    }

    UA_NODESTORE_RELEASE(server, object);
    UA_NODESTORE_RELEASE(server, objectType);

    if(retval != UA_STATUSCODE_BADNOTIMPLEMENTED)
        return retval;

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "File type functions are currently only supported for TrustList types");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static UA_StatusCode
writeFile(UA_Server *server,
         const UA_NodeId *sessionId, void *sessionHandle,
         const UA_NodeId *methodId, void *methodContext,
         const UA_NodeId *objectId, void *objectContext,
         size_t inputSize, const UA_Variant *input,
         size_t outputSize, UA_Variant *output) {

    const UA_Node *object = UA_NODESTORE_GET(server, objectId);
    if(!object)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    const UA_Node *objectType =
        getNodeType(server, &object->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);

    UA_NodeId trustListType = UA_NODEID_NUMERIC(0, UA_NS0ID_TRUSTLISTTYPE);
    UA_StatusCode retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
    if(UA_NodeId_equal(&objectType->head.nodeId, &trustListType)) {
        retval = writeTrustList(server, sessionId, sessionHandle, methodId, methodContext,
                                objectId, objectContext, inputSize, input, outputSize, output);
    }

    UA_NODESTORE_RELEASE(server, object);
    UA_NODESTORE_RELEASE(server, objectType);

    if(retval != UA_STATUSCODE_BADNOTIMPLEMENTED)
        return retval;

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "File type functions are currently only supported for TrustList types");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static UA_StatusCode
closeFile(UA_Server *server,
         const UA_NodeId *sessionId, void *sessionHandle,
         const UA_NodeId *methodId, void *methodContext,
         const UA_NodeId *objectId, void *objectContext,
         size_t inputSize, const UA_Variant *input,
         size_t outputSize, UA_Variant *output) {

    const UA_Node *object = UA_NODESTORE_GET(server, objectId);
    if(!object)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    const UA_Node *objectType =
        getNodeType(server, &object->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);

    UA_NodeId trustListType = UA_NODEID_NUMERIC(0, UA_NS0ID_TRUSTLISTTYPE);
    UA_StatusCode retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
    if(UA_NodeId_equal(&objectType->head.nodeId, &trustListType)) {
        retval = closeTrustList(server, sessionId, sessionHandle, methodId, methodContext,
                                objectId, objectContext, inputSize, input, outputSize, output);
    }

    UA_NODESTORE_RELEASE(server, object);
    UA_NODESTORE_RELEASE(server, objectType);

    if(retval != UA_STATUSCODE_BADNOTIMPLEMENTED)
        return retval;

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "File type functions are currently only supported for TrustList types");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static UA_StatusCode
getPositionFile(UA_Server *server,
         const UA_NodeId *sessionId, void *sessionHandle,
         const UA_NodeId *methodId, void *methodContext,
         const UA_NodeId *objectId, void *objectContext,
         size_t inputSize, const UA_Variant *input,
         size_t outputSize, UA_Variant *output) {

    const UA_Node *object = UA_NODESTORE_GET(server, objectId);
    if(!object)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    const UA_Node *objectType =
        getNodeType(server, &object->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);

    UA_NodeId trustListType = UA_NODEID_NUMERIC(0, UA_NS0ID_TRUSTLISTTYPE);
    UA_StatusCode retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
    if(UA_NodeId_equal(&objectType->head.nodeId, &trustListType)) {
        retval = getPositionTrustList(server, sessionId, sessionHandle, methodId, methodContext,
                                      objectId, objectContext, inputSize, input, outputSize, output);
    }

    UA_NODESTORE_RELEASE(server, object);
    UA_NODESTORE_RELEASE(server, objectType);

    if(retval != UA_STATUSCODE_BADNOTIMPLEMENTED)
        return retval;

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "File type functions are currently only supported for TrustList types");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static UA_StatusCode
setPositionFile(UA_Server *server,
         const UA_NodeId *sessionId, void *sessionHandle,
         const UA_NodeId *methodId, void *methodContext,
         const UA_NodeId *objectId, void *objectContext,
         size_t inputSize, const UA_Variant *input,
         size_t outputSize, UA_Variant *output) {

    const UA_Node *object = UA_NODESTORE_GET(server, objectId);
    if(!object)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    const UA_Node *objectType =
        getNodeType(server, &object->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);

    UA_NodeId trustListType = UA_NODEID_NUMERIC(0, UA_NS0ID_TRUSTLISTTYPE);
    UA_StatusCode retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
    if(UA_NodeId_equal(&objectType->head.nodeId, &trustListType)) {
        retval = setPositionTrustList(server, sessionId, sessionHandle, methodId, methodContext,
                                      objectId, objectContext, inputSize, input, outputSize, output);
    }

    UA_NODESTORE_RELEASE(server, object);
    UA_NODESTORE_RELEASE(server, objectType);

    if(retval != UA_STATUSCODE_BADNOTIMPLEMENTED)
        return retval;

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "File type functions are currently only supported for TrustList types");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static UA_StatusCode
updateCertificateAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = updateCertificate(server, sessionId, sessionHandle,
                                          methodId, methodContext,
                                          objectId, objectContext,
                                          inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
createSigningRequestAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = createSigningRequest(server, sessionId, sessionHandle,
                                             methodId, methodContext,
                                             objectId, objectContext,
                                             inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
getRejectedListAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = getRejectedList(server, sessionId, sessionHandle,
                                        methodId, methodContext,
                                        objectId, objectContext,
                                        inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
applyChangesAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = applyChanges(server, sessionId, sessionHandle,
                                     methodId, methodContext,
                                     objectId, objectContext,
                                     inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
addCertificateAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = addCertificate(server, sessionId, sessionHandle,
                                       methodId, methodContext,
                                       objectId, objectContext,
                                       inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
removeCertificateAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = removeCertificate(server, sessionId, sessionHandle,
                                          methodId, methodContext,
                                          objectId, objectContext,
                                          inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
openTrustListWithMaskAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = openTrustListWithMask(server, sessionId, sessionHandle,
                                              methodId, methodContext,
                                              objectId, objectContext,
                                              inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
closeAndUpdateTrustListAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = closeAndUpdateTrustList(server, sessionId, sessionHandle,
                                                methodId, methodContext,
                                                objectId, objectContext,
                                                inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
openFileAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = openFile(server, sessionId, sessionHandle,
                                 methodId, methodContext,
                                 objectId, objectContext,
                                 inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
readFileAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = readFile(server, sessionId, sessionHandle,
                                 methodId, methodContext,
                                 objectId, objectContext,
                                 inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
writeFileAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = writeFile(server, sessionId, sessionHandle,
                                  methodId, methodContext,
                                  objectId, objectContext,
                                  inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
closeFileAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = closeFile(server, sessionId, sessionHandle,
                                  methodId, methodContext,
                                  objectId, objectContext,
                                  inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
getPositionFileAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = getPositionFile(server, sessionId, sessionHandle,
                                        methodId, methodContext,
                                        objectId, objectContext,
                                        inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

static UA_StatusCode
setPositionFileAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionHandle,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output) {
    lockServer(server);
    UA_StatusCode res = setPositionFile(server, sessionId, sessionHandle,
                                        methodId, methodContext,
                                        objectId, objectContext,
                                        inputSize, input, outputSize, output);
    unlockServer(server);
    return res;
}

UA_StatusCode
initNS0PushManagement(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    /* Create FileInfo */
    retval |= createFileInfoContexts(server);

    /* Set variables */
    retval |= writeGroupVariables(server);

    /* Set method callbacks */
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_UPDATECERTIFICATE), updateCertificateAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CREATESIGNINGREQUEST), createSigningRequestAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_GETREJECTEDLIST), getRejectedListAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_APPLYCHANGES), applyChangesAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_ADDCERTIFICATE), addCertificateAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_ADDCERTIFICATE), addCertificateAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_REMOVECERTIFICATE), removeCertificateAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_REMOVECERTIFICATE), removeCertificateAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_OPENWITHMASKS), openTrustListWithMaskAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_OPENWITHMASKS), openTrustListWithMaskAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_CLOSEANDUPDATE), closeAndUpdateTrustListAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_CLOSEANDUPDATE), closeAndUpdateTrustListAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_OPEN), openFileAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_OPEN), openFileAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_READ), readFileAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_READ), readFileAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_WRITE), writeFileAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_WRITE), writeFileAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_CLOSE), closeFileAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_CLOSE), closeFileAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_GETPOSITION), getPositionFileAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_GETPOSITION), getPositionFileAction);

    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST_SETPOSITION), setPositionFileAction);
    retval |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST_SETPOSITION), setPositionFileAction);

    return retval;
}

#endif

/**** amalgamated original file "/src/server/ua_server_config.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */



void
UA_ServerConfig_clear(UA_ServerConfig *config) {
    if(!config)
        return;

    /* Server Description */
    UA_BuildInfo_clear(&config->buildInfo);
    UA_ApplicationDescription_clear(&config->applicationDescription);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_MdnsDiscoveryConfiguration_clear(&config->mdnsConfig);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD
    UA_String_clear(&config->mdnsInterfaceIP);
# if !defined(UA_HAS_GETIFADDR)
    if (config->mdnsIpAddressListSize) {
        UA_free(config->mdnsIpAddressList);
    }
# endif
#endif
#endif

    /* Stop and delete the EventLoop */
    UA_EventLoop *el = config->eventLoop;
    if(el && !config->externalEventLoop) {
        if(el->state != UA_EVENTLOOPSTATE_FRESH &&
           el->state != UA_EVENTLOOPSTATE_STOPPED) {
            el->stop(el);
            while(el->state != UA_EVENTLOOPSTATE_STOPPED) {
                el->run(el, 100);
            }
        }
        el->free(el);
        config->eventLoop = NULL;
    }

    /* Networking */
    UA_Array_delete(config->serverUrls, config->serverUrlsSize,
                    &UA_TYPES[UA_TYPES_STRING]);
    config->serverUrls = NULL;
    config->serverUrlsSize = 0;

    /* Security Policies */
    for(size_t i = 0; i < config->securityPoliciesSize; ++i) {
        UA_SecurityPolicy *policy = &config->securityPolicies[i];
        policy->clear(policy);
    }
    UA_free(config->securityPolicies);
    config->securityPolicies = NULL;
    config->securityPoliciesSize = 0;

    for(size_t i = 0; i < config->endpointsSize; ++i)
        UA_EndpointDescription_clear(&config->endpoints[i]);

    UA_free(config->endpoints);
    config->endpoints = NULL;
    config->endpointsSize = 0;

    /* Nodestore */
    if(config->nodestore) {
        config->nodestore->free(config->nodestore);
        config->nodestore = NULL;
    }

    /* Certificate Validation */
    if(config->secureChannelPKI.clear)
        config->secureChannelPKI.clear(&config->secureChannelPKI);
    if(config->sessionPKI.clear)
        config->sessionPKI.clear(&config->sessionPKI);

    /* Access Control */
    if(config->accessControl.clear)
        config->accessControl.clear(&config->accessControl);

    /* Historical data */
#ifdef UA_ENABLE_HISTORIZING
    if(config->historyDatabase.clear)
        config->historyDatabase.clear(&config->historyDatabase);
#endif

#ifdef UA_ENABLE_PUBSUB
    if(config->pubSubConfig.securityPolicies != NULL) {
        for(size_t i = 0; i < config->pubSubConfig.securityPoliciesSize; i++) {
            config->pubSubConfig.securityPolicies[i].clear(&config->pubSubConfig.securityPolicies[i]);
        }
        UA_free(config->pubSubConfig.securityPolicies);
        config->pubSubConfig.securityPolicies = NULL;
        config->pubSubConfig.securityPoliciesSize = 0;
    }
#endif /* UA_ENABLE_PUBSUB */

    /* Logger */
    if(config->logging != NULL && config->logging->clear != NULL)
        config->logging->clear(config->logging);
    config->logging = NULL;

    /* Custom Data Types */
    UA_cleanupDataTypeWithCustom(config->customDataTypes);
    config->customDataTypes = NULL;
}

/**** amalgamated original file "/src/server/ua_server_binary.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014-2015, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Joakim L. Gilje
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2023 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Phuong Nguyen)
 */



#ifdef UA_DEBUG_DUMP_PKGS_FILE
void UA_debug_dumpCompleteChunk(UA_Server *const server, UA_Connection *const connection,
                                UA_ByteString *messageBuffer);
#endif

/************************************/
/* Binary Protocol Server Component */
/************************************/

/* Maximum numbers of sockets to listen on */
#define UA_MAXSERVERCONNECTIONS 16

typedef struct {
    UA_ConnectionState state;
    uintptr_t connectionId;
    UA_ConnectionManager *connectionManager;
} UA_ServerConnection;

/* Reverse connect */
typedef struct reverse_connect_context {
    UA_String hostname;
    UA_UInt16 port;
    UA_UInt64 handle;

    UA_SecureChannelState state;
    UA_Server_ReverseConnectStateCallback stateCallback;
    void *callbackContext;

     /* If this is set to true, the reverse connection is removed/freed when the
      * connection closes. Otherwise we try to reconnect when the connection
      * closes. */
    UA_Boolean destruction;

    UA_ServerConnection currentConnection;
    UA_SecureChannel *channel;
    LIST_ENTRY(reverse_connect_context) next;
} reverse_connect_context;

/* Binary Protocol Manager */
typedef struct {
    UA_ServerComponent sc;
    const UA_Logger *logging; /* shortcut */
    UA_UInt64 houseKeepingCallbackId;

    UA_ServerConnection serverConnections[UA_MAXSERVERCONNECTIONS];
    size_t serverConnectionsSize;

    UA_ConnectionConfig tcpConnectionConfig; /* Extracted from the server config
                                              * parameters */

    /* SecureChannels */
    TAILQ_HEAD(, UA_SecureChannel) channels;

    /* Reverse Connections */
    LIST_HEAD(, reverse_connect_context) reverseConnects;
    UA_UInt64 reverseConnectsCheckHandle;
    UA_UInt64 lastReverseConnectHandle;
} UA_BinaryProtocolManager;

void setReverseConnectState(UA_Server *server, reverse_connect_context *context,
                            UA_SecureChannelState newState);
UA_StatusCode attemptReverseConnect(UA_BinaryProtocolManager *bpm,
                                    reverse_connect_context *context);
UA_StatusCode setReverseConnectRetryCallback(UA_BinaryProtocolManager *bpm,
                                             UA_Boolean enabled);

/********************/
/* Helper Functions */
/********************/

static void
setBinaryProtocolManagerState(UA_BinaryProtocolManager *bpm,
                              UA_LifecycleState state) {
    if(state == bpm->sc.state)
        return;
    bpm->sc.state = state;
    if(bpm->sc.notifyState)
        bpm->sc.notifyState(&bpm->sc, state);
}

static void
deleteServerSecureChannel(UA_BinaryProtocolManager *bpm,
                          UA_SecureChannel *channel) {
    UA_Server *server = bpm->sc.server;
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Clean up the SecureChannel. This is the only place where
     * UA_SecureChannel_clear must be called within the server code-base.
     *
     * Activated sessions are detached so they can be re-activated on a new
     * channel. Non-activated sessions are deleted (Part 4, §5.6.3). */
    while(channel->sessions) {
        UA_Session *session = channel->sessions;
        if(!session->activated)
            UA_Session_remove(server, session, UA_SHUTDOWNREASON_PURGE);
        else
            UA_Session_detachFromSecureChannel(server, session);
    }

    /* Detach the channel from the server list */
    TAILQ_REMOVE(&server->channels, channel, serverEntry);
    TAILQ_REMOVE(&bpm->channels, channel, componentEntry);

    /* Update the statistics */
    UA_SecureChannelStatistics *scs = &server->secureChannelStatistics;
    scs->currentChannelCount--;
    switch(channel->shutdownReason) {
    case UA_SHUTDOWNREASON_CLOSE:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel closed");
        break;
    case UA_SHUTDOWNREASON_TIMEOUT:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel closed due to timeout");
        scs->channelTimeoutCount++;
        break;
    case UA_SHUTDOWNREASON_PURGE:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel was purged");
        scs->channelPurgeCount++;
        break;
    case UA_SHUTDOWNREASON_REJECT:
    case UA_SHUTDOWNREASON_SECURITYREJECT:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel was rejected");
        scs->rejectedChannelCount++;
        break;
    case UA_SHUTDOWNREASON_ABORT:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel was aborted");
        scs->channelAbortCount++;
        break;
    default:
        UA_assert(false);
        break;
    }

    /* Notify the application */
    notifySecureChannel(server, channel,
                        UA_APPLICATIONNOTIFICATIONTYPE_SECURECHANNEL_CLOSED);

    /* Clean up the SecureChannel. This is the only place where
     * UA_SecureChannel_clear must be called within the server code-base. */
    UA_SecureChannel_clear(channel);
    UA_free(channel);
}

UA_StatusCode
sendServiceFault(UA_Server *server, UA_SecureChannel *channel,
                 UA_UInt32 requestId, UA_UInt32 requestHandle,
                 UA_StatusCode statusCode) {
    UA_EventLoop *el = server->config.eventLoop;

    UA_ServiceFault response;
    UA_ServiceFault_init(&response);
    UA_ResponseHeader *responseHeader = &response.responseHeader;
    responseHeader->requestHandle = requestHandle;
    responseHeader->timestamp = el->dateTime_now(el);
    responseHeader->serviceResult = statusCode;

    UA_LOG_DEBUG(channel->securityPolicy->logger, UA_LOGCATEGORY_SERVER,
                 "Sending response for RequestId %u with ServiceResult %s",
                 (unsigned)requestId, UA_StatusCode_name(statusCode));

    /* Send error message. Message type is MSG and not ERR, since we are on a
     * SecureChannel! */
    return UA_SecureChannel_sendMSG(channel, requestId, &response,
                                    &UA_TYPES[UA_TYPES_SERVICEFAULT]);
}

/* This is not an ERR message, the connection is not closed afterwards */
static UA_StatusCode
decodeHeaderSendServiceFault(UA_Server *server, UA_SecureChannel *channel,
                             const UA_ByteString *msg, size_t offset,
                             const UA_DataType *responseType, UA_UInt32 requestId,
                             UA_StatusCode error) {
    UA_RequestHeader requestHeader;
    UA_StatusCode retval =
        UA_decodeBinaryInternal(msg, &offset, &requestHeader,
                                &UA_TYPES[UA_TYPES_REQUESTHEADER], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    retval = sendServiceFault(server, channel, requestId,
                              requestHeader.requestHandle, error);
    UA_RequestHeader_clear(&requestHeader);
    return retval;
}

/*************************/
/* Process Message Types */
/*************************/

/* HEL -> Open up the connection */
static UA_StatusCode
processHEL(UA_Server *server, UA_SecureChannel *channel, const UA_ByteString *msg) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_ConnectionManager *cm = channel->connectionManager;
    if(!cm || (channel->state != UA_SECURECHANNELSTATE_CONNECTED &&
               channel->state != UA_SECURECHANNELSTATE_RHE_SENT))
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t offset = 0; /* Go to the beginning of the TcpHelloMessage */
    UA_TcpHelloMessage helloMessage;
    UA_StatusCode retval =
        UA_decodeBinaryInternal(msg, &offset, &helloMessage,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Currently not checked */
    UA_String_copy(&helloMessage.endpointUrl, &channel->endpointUrl);
    UA_String_clear(&helloMessage.endpointUrl);

    /* Parameterize the connection. The TcpHelloMessage casts to a
     * TcpAcknowledgeMessage. */
    retval = UA_SecureChannel_processHELACK(channel,
                                            (UA_TcpAcknowledgeMessage*)&helloMessage);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                            "Error during the HEL/ACK handshake");
        return retval;
    }

    /* Get the send buffer from the network layer */
    UA_ByteString ack_msg;
    UA_ByteString_init(&ack_msg);
    retval = cm->allocNetworkBuffer(cm, channel->connectionId,
                                    &ack_msg, channel->config.sendBufferSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Build acknowledge response */
    UA_TcpAcknowledgeMessage ackMessage;
    ackMessage.protocolVersion = 0;
    ackMessage.receiveBufferSize = channel->config.recvBufferSize;
    ackMessage.sendBufferSize = channel->config.sendBufferSize;
    ackMessage.maxMessageSize = channel->config.localMaxMessageSize;
    ackMessage.maxChunkCount = channel->config.localMaxChunkCount;

    UA_TcpMessageHeader ackHeader;
    ackHeader.messageTypeAndChunkType = UA_MESSAGETYPE_ACK + UA_CHUNKTYPE_FINAL;
    ackHeader.messageSize = 8 + 20; /* ackHeader + ackMessage */

    /* Encode and send the response */
    UA_Byte *bufPos = ack_msg.data;
    const UA_Byte *bufEnd = &ack_msg.data[ack_msg.length];
    retval |= UA_encodeBinaryInternal(&ackHeader,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                      &bufPos, &bufEnd, NULL, NULL, NULL);
    retval |= UA_encodeBinaryInternal(&ackMessage,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE],
                                      &bufPos, &bufEnd, NULL, NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, channel->connectionId, &ack_msg);
        return retval;
    }

    ack_msg.length = ackHeader.messageSize;
    retval = cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &ack_msg);
    if(retval == UA_STATUSCODE_GOOD)
        channel->state = UA_SECURECHANNELSTATE_ACK_SENT;
    return retval;
}

/* OPN -> Open up/renew the securechannel */
static UA_StatusCode
processOPN(UA_Server *server, UA_SecureChannel *channel,
           const UA_UInt32 requestId, const UA_ByteString *msg) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT &&
       channel->state != UA_SECURECHANNELSTATE_OPEN)
        return UA_STATUSCODE_BADINTERNALERROR;
    /* Decode the request */
    UA_NodeId requestType;
    UA_OpenSecureChannelRequest openSecureChannelRequest;
    size_t offset = 0;
    UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestType);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_NodeId_clear(&requestType);
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not decode the NodeId. "
                               "Closing the SecureChannel.");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
        return retval;
    }
    retval = UA_decodeBinaryInternal(msg, &offset, &openSecureChannelRequest,
                                     &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST], NULL);

    /* Error occurred */
    const UA_NodeId *opnRequestId =
        &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId;
    if(retval != UA_STATUSCODE_GOOD || !UA_NodeId_equal(&requestType, opnRequestId)) {
        UA_NodeId_clear(&requestType);
        UA_OpenSecureChannelRequest_clear(&openSecureChannelRequest);
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not decode the OPN message. "
                               "Closing the SecureChannel.");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
        return retval;
    }
    UA_NodeId_clear(&requestType);

    /* Call the service */
    UA_OpenSecureChannelResponse openScResponse;
    UA_OpenSecureChannelResponse_init(&openScResponse);
    Service_OpenSecureChannel(server, channel, &openSecureChannelRequest, &openScResponse);
    UA_OpenSecureChannelRequest_clear(&openSecureChannelRequest);
    if(openScResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not open a SecureChannel. "
                               "Closing the connection.");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
        return openScResponse.responseHeader.serviceResult;
    }

    /* Send the response */
    retval = UA_SecureChannel_sendOPN(channel, requestId, &openScResponse,
                                      &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    UA_OpenSecureChannelResponse_clear(&openScResponse);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not send the OPN answer with error code %s",
                               UA_StatusCode_name(retval));
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
    }

    return retval;
}

/* The responseHeader must have the requestHandle already set */
UA_StatusCode
sendResponse(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId,
             UA_Response *response, const UA_DataType *responseType) {
    if(!channel)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* If the overall service call failed, answer with a ServiceFault */
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return sendServiceFault(server, channel, requestId,
                                response->responseHeader.requestHandle,
                                response->responseHeader.serviceResult);

    /* Prepare the ResponseHeader */
    UA_EventLoop *el = server->config.eventLoop;
    response->responseHeader.timestamp = el->dateTime_now(el);

    /* Start the message context */
    UA_MessageContext mc;
    UA_StatusCode retval = UA_MessageContext_begin(&mc, channel, requestId, UA_MESSAGETYPE_MSG);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Assert's required for clang-analyzer */
    UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]);
    UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]);

    /* Encode the response type */
    retval = UA_MessageContext_encode(&mc, &responseType->binaryEncodingId,
                                      &UA_TYPES[UA_TYPES_NODEID]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Encode the response */
    retval = UA_MessageContext_encode(&mc, response, responseType);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Finish / send out */
    return UA_MessageContext_finish(&mc);
}

/* A Session is "bound" to a SecureChannel if it was created by the
 * SecureChannel or if it was activated on it. A Session can only be bound to
 * one SecureChannel. A Session can only be closed from the SecureChannel to
 * which it is bound.
 *
 * Returns Good if the AuthenticationToken exists nowhere (for CTT). */
UA_StatusCode
getBoundSession(UA_Server *server, const UA_SecureChannel *channel,
                const UA_NodeId *token, UA_Session **session) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);

    for(UA_Session *s = channel->sessions; s; s = s->next) {
        if(!UA_NodeId_equal(token, &s->authenticationToken))
            continue;

        /* Has the session timed out? */
        if(s->validTill < nowMonotonic)
            return UA_STATUSCODE_BADSESSIONCLOSED;

        /* Return the session */
        *session = s;
        return UA_STATUSCODE_GOOD;
    }

    /* Session exists on another SecureChannel */
    UA_Session *tmpSession = getSessionByToken(server, token);
    if(tmpSession) {
#ifdef UA_ENABLE_DIAGNOSTICS
        tmpSession->diagnostics.unauthorizedRequestCount++;
#endif
        return UA_STATUSCODE_BADSECURECHANNELIDINVALID;
    }

    /* The StatusCode indicates if the Session doesn't exist or whether it does
     * not match to SecureChannel */
    return UA_STATUSCODE_BADSESSIONIDINVALID;
}

static UA_StatusCode
processMSG(UA_Server *server, UA_SecureChannel *channel,
           UA_UInt32 requestId, const UA_ByteString *msg) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(channel->state != UA_SECURECHANNELSTATE_OPEN)
        return UA_STATUSCODE_BADINTERNALERROR;
    /* Decode the nodeid */
    size_t offset = 0;
    UA_NodeId requestTypeId;
    UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestTypeId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    if(requestTypeId.namespaceIndex != 0 ||
       requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC)
        UA_NodeId_clear(&requestTypeId); /* leads to badserviceunsupported */

    /* Get the service pointers */
    UA_ServiceDescription *sd = getServiceDescription(requestTypeId.identifier.numeric);
    if(!sd) {
        if(requestTypeId.identifier.numeric ==
           UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY) {
            UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                                "Client requested a subscription, "
                                "but those are not enabled in the build");
        } else {
            UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                                "Unknown request with type identifier %" PRIi32,
                                requestTypeId.identifier.numeric);
        }
        return decodeHeaderSendServiceFault(server, channel, msg, offset,
                                            &UA_TYPES[UA_TYPES_SERVICEFAULT],
                                            requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
    }

    /* Decode the request */
    UA_Request request;
    size_t requestPos = offset; /* Store the offset (for sendServiceFault) */
    UA_DecodeBinaryOptions opt;
    memset(&opt, 0, sizeof(UA_DecodeBinaryOptions));
    opt.customTypes = serverCustomTypes(server);
    retval = UA_decodeBinaryInternal(msg, &offset, &request, sd->requestType, &opt);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_DEBUG_CHANNEL(server->config.logging, channel,
                             "Could not decode the request with StatusCode %s",
                             UA_StatusCode_name(retval));
        return decodeHeaderSendServiceFault(server, channel, msg, requestPos,
                                            sd->responseType, requestId, retval);
    }

    /* Initialize the response */
    UA_Response response;
    UA_init(&response, sd->responseType);
    response.responseHeader.requestHandle = request.requestHeader.requestHandle;

    lockServer(server);

    /* Process the request */
    UA_Boolean done = processRequest(server, channel, requestId, sd, &request, &response);

    /* Send response if not async */
    if(UA_LIKELY(done))
        retval = sendResponse(server, channel, requestId, &response, sd->responseType);

    unlockServer(server);

    /* Clean up */
    UA_clear(&request, sd->requestType);
    UA_clear(&response, sd->responseType);
    return retval;
}

/* Takes decoded messages starting at the nodeid of the content type. */
static UA_StatusCode
processSecureChannelMessage(UA_Server *server, UA_SecureChannel *channel,
                            UA_MessageType messagetype, UA_UInt32 requestId,
                            UA_ByteString *message) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(messagetype) {
    case UA_MESSAGETYPE_HEL:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process a HEL message");
        retval = processHEL(server, channel, message);
        break;
    case UA_MESSAGETYPE_OPN:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process an OPN message");
        retval = processOPN(server, channel, requestId, message);
        break;
    case UA_MESSAGETYPE_MSG:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process a MSG");
        retval = processMSG(server, channel, requestId, message);
        break;
    case UA_MESSAGETYPE_CLO:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process a CLO");
        Service_CloseSecureChannel(server, channel); /* Regular close */
        break;
    default:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Invalid message type");
        retval = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        break;
    }
    if(retval != UA_STATUSCODE_GOOD) {
        if(!UA_SecureChannel_isConnected(channel)) {
            UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                                "Processing the message failed. Channel already closed "
                                "with StatusCode %s. ", UA_StatusCode_name(retval));
            return retval;
        }

        UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                            "Processing the message failed with StatusCode %s. "
                            "Closing the channel.", UA_StatusCode_name(retval));
        UA_TcpErrorMessage errMsg;
        UA_TcpErrorMessage_init(&errMsg);
        errMsg.error = retval;
        UA_SecureChannel_sendERR(channel, &errMsg);
        UA_ShutdownReason reason;
        switch(retval) {
        case UA_STATUSCODE_BADSECURITYMODEREJECTED:
        case UA_STATUSCODE_BADSECURITYCHECKSFAILED:
        case UA_STATUSCODE_BADSECURECHANNELIDINVALID:
        case UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN:
        case UA_STATUSCODE_BADSECURITYPOLICYREJECTED:
        case UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED:
            reason = UA_SHUTDOWNREASON_SECURITYREJECT;
            break;
        default:
            reason = UA_SHUTDOWNREASON_CLOSE;
            break;
        }
        UA_SecureChannel_shutdown(channel, reason);
    }

    return retval;
}

/* remove the first channel that has no session attached */
static UA_Boolean
purgeFirstChannelWithoutSession(UA_BinaryProtocolManager *bpm) {
    UA_SecureChannel *channel;
    TAILQ_FOREACH(channel, &bpm->channels, componentEntry) {
        if(channel->sessions)
            continue;
        UA_LOG_INFO_CHANNEL(bpm->logging, channel,
                            "Channel was purged since maxSecureChannels was "
                            "reached and channel had no session attached");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_PURGE);
        return true;
    }
    return false;
}

static UA_StatusCode
createServerSecureChannel(UA_BinaryProtocolManager *bpm, UA_ConnectionManager *cm,
                          uintptr_t connectionId, const UA_KeyValueMap *params,
                          UA_SecureChannel **outChannel) {
    UA_Server *server = bpm->sc.server;
    UA_ServerConfig *config = &server->config;
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check if we have space for another SC, otherwise try to find an SC
     * without a session and purge it */
    UA_SecureChannelStatistics *scs = &server->secureChannelStatistics;
    if(scs->currentChannelCount >= config->maxSecureChannels &&
       !purgeFirstChannelWithoutSession(bpm))
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Allocate memory for the SecureChannel */
    UA_SecureChannel *channel = (UA_SecureChannel*)UA_calloc(1, sizeof(UA_SecureChannel));
    if(!channel)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set up the initial connection config */
    UA_ConnectionConfig connConfig;
    connConfig.protocolVersion = 0;
    connConfig.recvBufferSize = config->tcpBufSize;
    connConfig.sendBufferSize = config->tcpBufSize;
    connConfig.localMaxMessageSize = config->tcpMaxMsgSize;
    connConfig.remoteMaxMessageSize = config->tcpMaxMsgSize;
    connConfig.localMaxChunkCount = config->tcpMaxChunks;
    connConfig.remoteMaxChunkCount = config->tcpMaxChunks;

    /* Further constrain the bufsize if the ConnectionManager has static rx/tx
     * buffers configured */
    const UA_UInt32 *bufSize = (const UA_UInt32 *)
        UA_KeyValueMap_getScalar(&cm->eventSource.params,
                                 UA_QUALIFIEDNAME(0, "recv-bufsize"),
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(bufSize && *bufSize < connConfig.recvBufferSize)
        connConfig.recvBufferSize = *bufSize;
    bufSize = (const UA_UInt32 *)
        UA_KeyValueMap_getScalar(&cm->eventSource.params,
                                 UA_QUALIFIEDNAME(0, "send-bufsize"),
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(bufSize && *bufSize < connConfig.sendBufferSize)
        connConfig.sendBufferSize = *bufSize;

    /* Set upper bounds if not configured */
    if(connConfig.recvBufferSize == 0)
        connConfig.recvBufferSize = 1 << 16; /* 64kB */
    if(connConfig.sendBufferSize == 0)
        connConfig.sendBufferSize = 1 << 16; /* 64kB */
    if(connConfig.localMaxMessageSize == 0)
        connConfig.localMaxMessageSize = 1 << 29; /* 512 MB */
    if(connConfig.remoteMaxMessageSize == 0)
        connConfig.remoteMaxMessageSize = 1 << 29; /* 512 MB */
    if(connConfig.localMaxChunkCount == 0)
        connConfig.localMaxChunkCount = 1 << 14; /* 16384 */
    if(connConfig.remoteMaxChunkCount == 0)
        connConfig.remoteMaxChunkCount = 1 << 14; /* 16384 */

    /* Set up the new SecureChannel */
    UA_SecureChannel_init(channel);
    channel->config = connConfig;
    channel->processOPNHeader = processOPN_AsymHeader;
    channel->processOPNHeaderApplication = server;
    channel->connectionManager = cm;
    channel->connectionId = connectionId;

    /* The remote addresss is given in the very first callback from the
     * ConnectionManager. */
    if(params) {
        const UA_String *address = (const UA_String *)
            UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "remote-address"),
                                     &UA_TYPES[UA_TYPES_STRING]);
        if(address)
            UA_String_copy(address, &channel->remoteAddress);
    }

    /* Set the SecureChannel identifier already here. So we get the right
     * identifier for logging right away. The rest of the SecurityToken is set
     * in UA_SecureChannelManager_open. Set the ChannelId also in the
     * alternative security token, we don't touch this value during the token
     * rollover. */
    channel->securityToken.channelId = server->lastChannelId++;

    /* Set an initial timeout before the negotiation handshake. So the channel
     * is caught if the client is unresponsive.
     *
     * TODO: Make this a configuration option */
    UA_EventLoop *el = server->config.eventLoop;
    channel->securityToken.createdAt = el->dateTime_nowMonotonic(el);
    channel->securityToken.revisedLifetime = 10000; /* 10s should be enough */

    /* Add to the server's list */
    TAILQ_INSERT_TAIL(&server->channels, channel, serverEntry);
    TAILQ_INSERT_TAIL(&bpm->channels, channel, componentEntry);

    /* Update the statistics */
    server->secureChannelStatistics.currentChannelCount++;
    server->secureChannelStatistics.cumulatedChannelCount++;

    *outChannel = channel;
    return UA_STATUSCODE_GOOD;
}

static void
addDiscoveryUrl(UA_Server *server, const UA_String hostname, UA_UInt16 port) {
    char urlstr[1024];
    mp_snprintf(urlstr, 1024, "opc.tcp://%S:%d", hostname, port);
    UA_String discoveryServerUrl = UA_STRING(urlstr);

    /* Check if the ServerUrl is already present in the DiscoveryUrl array.
     * Add if not already there. */
    for(size_t i = 0; i < server->config.applicationDescription.discoveryUrlsSize; i++) {
        if(UA_String_equal(&discoveryServerUrl,
                           &server->config.applicationDescription.discoveryUrls[i]))
            return;
    }

    /* Add to the list of discovery url */
    UA_StatusCode res =
        UA_Array_appendCopy((void **)&server->config.applicationDescription.discoveryUrls,
                            &server->config.applicationDescription.discoveryUrlsSize,
                            &discoveryServerUrl, &UA_TYPES[UA_TYPES_STRING]);
    if(res == UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "New DiscoveryUrl added: %S", discoveryServerUrl);
    } else {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Could not register DiscoveryUrl -- out of memory");
    }
}

/* Callback of a TCP socket (server socket or an active connection).
 *
 * The connectionContext points to one of two possible structures. A
 * double-pointer is used here, so we get re-assign the context to a different
 * memory location within the callback.
 *
 * - The server socket (listening) has an initial NULL context and then gets
 *   assigned to the appropriate UA_ServerConnection slot.
 * - The connection socket (active) initially points to the UA_ServerConnection
 *   slot and then gets assigned to the new SecureChannel instance. */
static void
serverNetworkCallbackLocked(UA_ConnectionManager *cm, uintptr_t connectionId,
                            void *application, void **connectionContext,
                            UA_ConnectionState state,
                            const UA_KeyValueMap *params,
                            UA_ByteString msg) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)application;
    UA_LOCK_ASSERT(&bpm->sc.server->serviceMutex);

    /* A server socket that is not yet registered in the server. Register it and
     * set the connection context to the pointer in the
     * bpm->serverConnections list. New connections on that server socket
     * inherit the context (and on the first callback we set the context of
     * client-connections to a SecureChannel). */
    if(*connectionContext == NULL) {
        /* The socket is closing without being previously registered -> ignore */
        if(state == UA_CONNECTIONSTATE_CLOSED ||
           state == UA_CONNECTIONSTATE_CLOSING)
            return;

        /* Cannot register */
        if(bpm->serverConnectionsSize >= UA_MAXSERVERCONNECTIONS) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "Cannot register server socket - too many already open");
            cm->closeConnection(cm, connectionId);
            return;
        }

        /* Find and use a free connection slot */
        bpm->serverConnectionsSize++;
        UA_ServerConnection *sc = bpm->serverConnections;
        while(sc->connectionId != 0)
            sc++;
        sc->state = state;
        sc->connectionId = connectionId;
        sc->connectionManager = cm;
        *connectionContext = (void*)sc; /* Set the context pointer in the connection */

        /* Add to the DiscoveryUrls */
        const UA_UInt16 *port = (const UA_UInt16*)
            UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "listen-port"),
                                     &UA_TYPES[UA_TYPES_UINT16]);
        const UA_String *address = (const UA_String*)
            UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "listen-address"),
                                     &UA_TYPES[UA_TYPES_STRING]);
        if(port && address)
            addDiscoveryUrl(bpm->sc.server, *address, *port);
        return;
    }

    /* Either sc or channel applies. See the comment before this function. */
    UA_ServerConnection *sc = (UA_ServerConnection*)*connectionContext;
    UA_SecureChannel *channel = (UA_SecureChannel*)*connectionContext;
    UA_Boolean serverSocket = (sc >= bpm->serverConnections &&
                               sc < &bpm->serverConnections[UA_MAXSERVERCONNECTIONS]);

    /* The connection is closing. This is the last callback for it. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        if(serverSocket) {
            /* Server socket is closed */
            sc->state = UA_CONNECTIONSTATE_CLOSED;
            sc->connectionId = 0;
            bpm->serverConnectionsSize--;
        } else {
            /* A connection attached to a SecureChannel is closing. This is the
             * only place where deleteSecureChannel must be used. */
            deleteServerSecureChannel(bpm, channel);
        }

        /* Set BinaryProtocolManager to STOPPED if it is STOPPING and the last
         * socket just closed */
        if(bpm->sc.state == UA_LIFECYCLESTATE_STOPPING &&
           bpm->serverConnectionsSize == 0 &&
           LIST_EMPTY(&bpm->reverseConnects) &&
           TAILQ_EMPTY(&bpm->channels)) {
           setBinaryProtocolManagerState(bpm, UA_LIFECYCLESTATE_STOPPED);
        }
        return;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(serverSocket) {
        /* A new connection is opening. This is the only place where
         * createSecureChannel is used. */
        retval = createServerSecureChannel(bpm, cm, connectionId, params, &channel);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "TCP %lu\t| Could not accept the connection with status %s",
                           (unsigned long)sc->connectionId, UA_StatusCode_name(retval));
            *connectionContext = NULL;
            cm->closeConnection(cm, connectionId);
            return;
        }

        /* Set the new channel as the new context for the connection */
        *connectionContext = (void*)channel;

        /* Set the channel state to CONNECTED until the HEL message is received */
        channel->state = UA_SECURECHANNELSTATE_CONNECTED;

        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel created");
    }

    /* Received a message on a normal connection */
#ifdef UA_DEBUG_DUMP_PKGS
    UA_dump_hex_pkg(message->data, message->length);
#endif
#ifdef UA_DEBUG_DUMP_PKGS_FILE
    UA_debug_dumpCompleteChunk(server, channel->connection, message);
#endif

    UA_EventLoop *el = bpm->sc.server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);

    /* Process all complete messages */
    retval = UA_SecureChannel_loadBuffer(channel, msg);
    while(UA_LIKELY(retval == UA_STATUSCODE_GOOD)) {
        UA_MessageType messageType;
        UA_UInt32 requestId = 0;
        UA_ByteString payload = UA_BYTESTRING_NULL;
        UA_Boolean copied = false;
        retval = UA_SecureChannel_getCompleteMessage(channel, &messageType, &requestId,
                                                     &payload, &copied, nowMonotonic);
        if(retval != UA_STATUSCODE_GOOD || payload.length == 0)
            break;
        retval = processSecureChannelMessage(bpm->sc.server, channel,
                                             messageType, requestId, &payload);
        if(copied)
            UA_ByteString_clear(&payload);
    }
    retval |= UA_SecureChannel_persistBuffer(channel);

    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(bpm->logging, channel,
                               "Processing the message failed with error %s",
                               UA_StatusCode_name(retval));

        /* Send an ERR message and close the connection */
        UA_TcpErrorMessage error;
        error.error = retval;
        error.reason = UA_STRING_NULL;
        UA_SecureChannel_sendERR(channel, &error);
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_ABORT);
    }
}

void
serverNetworkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                      void *application, void **connectionContext,
                      UA_ConnectionState state,
                      const UA_KeyValueMap *params,
                      UA_ByteString msg) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)application;
    lockServer(bpm->sc.server);
    serverNetworkCallbackLocked(cm, connectionId, application, connectionContext,
                                state, params, msg);
    unlockServer(bpm->sc.server);
}

static UA_StatusCode
createServerConnection(UA_BinaryProtocolManager *bpm, const UA_String *serverUrl) {
    UA_Server *server = bpm->sc.server;
    UA_ServerConfig *config = &server->config;

    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Extract the protocol, hostname and port from the url */
    UA_String hostname = UA_STRING_NULL;
    UA_String path = UA_STRING_NULL;
    UA_UInt16 port = 4840; /* default */
    UA_StatusCode res = UA_parseEndpointUrl(serverUrl, &hostname, &port, &path);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_String tcpString = UA_STRING("tcp");
    for(UA_EventSource *es = config->eventLoop->eventSources;
        es != NULL; es = es->next) {
        /* Is this a usable connection manager? */
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(!UA_String_equal(&tcpString, &cm->protocol))
            continue;

        /* Set up the parameters */
        UA_KeyValuePair params[4];
        size_t paramsSize = 3;

        params[0].key = UA_QUALIFIEDNAME(0, "port");
        UA_Variant_setScalar(&params[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);

        UA_Boolean listen = true;
        params[1].key = UA_QUALIFIEDNAME(0, "listen");
        UA_Variant_setScalar(&params[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);

        UA_Boolean reuseaddr = config->tcpReuseAddr;
        params[2].key = UA_QUALIFIEDNAME(0, "reuse");
        UA_Variant_setScalar(&params[2].value, &reuseaddr, &UA_TYPES[UA_TYPES_BOOLEAN]);

        /* The hostname is non-empty */
        if(hostname.length > 0) {
            params[3].key = UA_QUALIFIEDNAME(0, "address");
            UA_Variant_setArray(&params[3].value, &hostname, 1, &UA_TYPES[UA_TYPES_STRING]);
            paramsSize = 4;
        }

        UA_KeyValueMap paramsMap;
        paramsMap.map = params;
        paramsMap.mapSize = paramsSize;

        /* Open the server connection */
        res = cm->openConnection(cm, &paramsMap, bpm, NULL, serverNetworkCallback);
        if(res == UA_STATUSCODE_GOOD)
            return res;
    }

    return UA_STATUSCODE_BADINTERNALERROR;
}

/* Remove timed out SecureChannels */
static void
secureChannelHouseKeeping(UA_Server *server, void *context) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)context;
    lockServer(server);

    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);

    UA_SecureChannel *channel;
    TAILQ_FOREACH(channel, &bpm->channels, componentEntry) {
        UA_Boolean timeout = UA_SecureChannel_checkTimeout(channel, nowMonotonic);
        if(timeout) {
            UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel has timed out");
            UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_TIMEOUT);
        }
    }
    unlockServer(server);
}

/**********************/
/* Reverse Connection */
/**********************/

#define UA_MINMESSAGESIZE 8192

static UA_StatusCode
sendRHEMessage(UA_Server *server, uintptr_t connectionId,
               UA_ConnectionManager *cm) {
    UA_ServerConfig *config = UA_Server_getConfig(server);

    /* Get a buffer */
    UA_ByteString message;
    UA_StatusCode retval =
        cm->allocNetworkBuffer(cm, connectionId, &message, UA_MINMESSAGESIZE);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Prepare the RHE message and encode at offset 8 */
    UA_TcpReverseHelloMessage reverseHello;
    UA_TcpReverseHelloMessage_init(&reverseHello);
    reverseHello.serverUri = config->applicationDescription.applicationUri;
    if(config->applicationDescription.discoveryUrlsSize)
        reverseHello.endpointUrl = config->applicationDescription.discoveryUrls[0];

    UA_Byte *bufPos = &message.data[8]; /* skip the header */
    const UA_Byte *bufEnd = &message.data[message.length];
    UA_StatusCode result =
        UA_encodeBinaryInternal(&reverseHello,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE],
                                &bufPos, &bufEnd, NULL, NULL, NULL);

    if(result != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, connectionId, &message);
        return result;
    }

    /* Encode the message header at offset 0 */
    UA_TcpMessageHeader messageHeader;
    messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_RHE;
    messageHeader.messageSize = (UA_UInt32) ((uintptr_t)bufPos - (uintptr_t)message.data);
    bufPos = message.data;
    retval = UA_encodeBinaryInternal(&messageHeader,
                                     &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                     &bufPos, &bufEnd, NULL, NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, connectionId, &message);
        return retval;
    }

    /* Send the RHE message */
    message.length = messageHeader.messageSize;
    return cm->sendWithConnection(cm, connectionId, NULL, &message);
}

static void
retryReverseConnectCallback(UA_Server *server, void *context) {
    lockServer(server);

    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)context;

    reverse_connect_context *rc = NULL;
    LIST_FOREACH(rc, &bpm->reverseConnects, next) {
        if(rc->currentConnection.connectionId)
            continue;
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Attempt to reverse reconnect to %S:%d", rc->hostname, rc->port);
        attemptReverseConnect(bpm, rc);
    }

    unlockServer(server);
}

UA_StatusCode
setReverseConnectRetryCallback(UA_BinaryProtocolManager *bpm, UA_Boolean enabled) {
    UA_Server *server = bpm->sc.server;
    UA_ServerConfig *config = &server->config;

    if(enabled && !bpm->reverseConnectsCheckHandle) {
        UA_UInt32 reconnectInterval = config->reverseReconnectInterval ?
            config->reverseReconnectInterval : 15000;
        return addRepeatedCallback(server, retryReverseConnectCallback, bpm,
                                   reconnectInterval, &bpm->reverseConnectsCheckHandle);
    } else if(!enabled && bpm->reverseConnectsCheckHandle) {
        removeCallback(server, bpm->reverseConnectsCheckHandle);
        bpm->reverseConnectsCheckHandle = 0;
    }
    return UA_STATUSCODE_GOOD;
}

void
setReverseConnectState(UA_Server *server, reverse_connect_context *context,
                       UA_SecureChannelState newState) {
    if(context->state == newState)
        return;

    context->state = newState;

    if(context->stateCallback)
        context->stateCallback(server, context->handle, context->state,
                               context->callbackContext);
}

static void
serverReverseConnectCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                             void *application, void **connectionContext,
                             UA_ConnectionState state, const UA_KeyValueMap *params,
                             UA_ByteString msg);

UA_StatusCode
attemptReverseConnect(UA_BinaryProtocolManager *bpm, reverse_connect_context *context) {
    UA_Server *server = bpm->sc.server;
    UA_ServerConfig *config = &server->config;
    UA_EventLoop *el = config->eventLoop;

    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Find a TCP ConnectionManager */
    UA_String tcpString = UA_STRING_STATIC("tcp");
    for(UA_EventSource *es = el->eventSources; es != NULL; es = es->next) {
        /* Is this a usable connection manager? */
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;

        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(!UA_String_equal(&tcpString, &cm->protocol))
            continue;

        if(es->state != UA_EVENTSOURCESTATE_STARTED)
            continue;

        /* Set up the parameters */
        UA_KeyValuePair params[2];
        params[0].key = UA_QUALIFIEDNAME(0, "address");
        UA_Variant_setScalar(&params[0].value, &context->hostname,
                             &UA_TYPES[UA_TYPES_STRING]);
        params[1].key = UA_QUALIFIEDNAME(0, "port");
        UA_Variant_setScalar(&params[1].value, &context->port,
                             &UA_TYPES[UA_TYPES_UINT16]);
        UA_KeyValueMap kvm = {2, params};

        /* Open the connection */
        UA_StatusCode res = cm->openConnection(cm, &kvm, bpm, context,
                                               serverReverseConnectCallback);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Failed to create connection for reverse connect: %s\n",
                           UA_StatusCode_name(res));
        }
        return res;
    }

    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                   "No ConnectionManager found for reverse connect");
    return UA_STATUSCODE_BADINTERNALERROR;
}

UA_StatusCode
UA_Server_addReverseConnect(UA_Server *server, UA_String url,
                            UA_Server_ReverseConnectStateCallback stateCallback,
                            void *callbackContext, UA_UInt64 *handle) {
    UA_ServerConfig *config = UA_Server_getConfig(server);
    UA_ServerComponent *sc =
        getServerComponentByName(server, UA_STRING("binary"));
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)sc;
    if(!bpm) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                     "No BinaryProtocolManager configured");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Parse the reverse connect URL */
    UA_String hostname = UA_STRING_NULL;
    UA_UInt16 port = 0;
    UA_StatusCode res = UA_parseEndpointUrl(&url, &hostname, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "OPC UA URL is invalid: %S", url);
        return res;
    }

    /* Set up the reverse connection */
    reverse_connect_context *newContext = (reverse_connect_context *)
        UA_calloc(1, sizeof(reverse_connect_context));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_String_copy(&hostname, &newContext->hostname);
    newContext->port = port;
    newContext->handle = ++bpm->lastReverseConnectHandle;
    newContext->stateCallback = stateCallback;
    newContext->callbackContext = callbackContext;

    lockServer(server);

    /* Register the retry callback */
    setReverseConnectRetryCallback(bpm, true);

    /* Register the new reverse connection */
    LIST_INSERT_HEAD(&bpm->reverseConnects, newContext, next);

    if(handle)
        *handle = newContext->handle;

    /* Attempt to connect right away */
    res = attemptReverseConnect(bpm, newContext);

    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removeReverseConnect(UA_Server *server, UA_UInt64 handle) {
    UA_StatusCode result = UA_STATUSCODE_BADNOTFOUND;

    lockServer(server);

    UA_ServerComponent *sc =
        getServerComponentByName(server, UA_STRING("binary"));
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)sc;
    if(!bpm) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "No BinaryProtocolManager configured");
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    reverse_connect_context *rev, *temp;
    LIST_FOREACH_SAFE(rev, &bpm->reverseConnects, next, temp) {
        if(rev->handle != handle)
            continue;

        LIST_REMOVE(rev, next);

        /* Connected -> disconnect, otherwise free immediately */
        if(rev->currentConnection.connectionId) {
            UA_ConnectionManager *cm = rev->currentConnection.connectionManager;
            rev->destruction = true;
            cm->closeConnection(cm, rev->currentConnection.connectionId);
        } else {
            setReverseConnectState(server, rev, UA_SECURECHANNELSTATE_CLOSED);
            UA_String_clear(&rev->hostname);
            UA_free(rev);
        }
        result = UA_STATUSCODE_GOOD;
        break;
    }

    if(LIST_EMPTY(&bpm->reverseConnects))
        setReverseConnectRetryCallback(bpm, false);

    unlockServer(server);
    return result;
}

static void
serverReverseConnectCallbackLocked(UA_ConnectionManager *cm, uintptr_t connectionId,
                                   void *application, void **connectionContext,
                                   UA_ConnectionState state, const UA_KeyValueMap *params,
                                   UA_ByteString msg) {
    (void)params;
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)application;
    UA_LOCK_ASSERT(&bpm->sc.server->serviceMutex);

    UA_LOG_DEBUG(bpm->logging, UA_LOGCATEGORY_SERVER,
                 "Activity for reverse connect %lu with state %d",
                 (long unsigned)connectionId, state);

    reverse_connect_context *context = (reverse_connect_context *)*connectionContext;
    context->currentConnection.state = state;

    /* New connection */
    if(context->currentConnection.connectionId == 0) {
        context->currentConnection.connectionId = connectionId;
        context->currentConnection.connectionManager = cm;
        setReverseConnectState(bpm->sc.server, context, UA_SECURECHANNELSTATE_CONNECTING);
        /* Fall through -- e.g. if state == ESTABLISHED already */
    }

    /* The connection is closing. This is the last callback for it. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        if(context->channel) {
            deleteServerSecureChannel(bpm, context->channel);
            context->channel = NULL;
        }

        /* Delete the ReverseConnect entry */
        if(context->destruction) {
            setReverseConnectState(bpm->sc.server, context, UA_SECURECHANNELSTATE_CLOSED);
            LIST_REMOVE(context, next);
            UA_String_clear(&context->hostname);
            UA_free(context);

            /* Check if the Binary Protocol Manager is stopped */
            if(bpm->sc.state == UA_LIFECYCLESTATE_STOPPING &&
               bpm->serverConnectionsSize == 0 &&
               LIST_EMPTY(&bpm->reverseConnects) &&
               TAILQ_EMPTY(&bpm->channels)) {
                setBinaryProtocolManagerState(bpm, UA_LIFECYCLESTATE_STOPPED);
            }
            return;
        }

        /* Reset. Will be picked up in the regular retry callback. */
        context->currentConnection.connectionId = 0;
        setReverseConnectState(bpm->sc.server, context, UA_SECURECHANNELSTATE_CONNECTING);
        return;
    }

    if(state != UA_CONNECTIONSTATE_ESTABLISHED)
        return;

    /* A new connection is opening. This is the only place where
     * createSecureChannel is used. */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(!context->channel) {
        retval = createServerSecureChannel(bpm, cm, connectionId, params,
                                           &context->channel);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "TCP %lu\t| Could not accept the reverse "
                           "connection with status %s",
                           (unsigned long)context->currentConnection.connectionId,
                           UA_StatusCode_name(retval));
            cm->closeConnection(cm, connectionId);
            return;
        }

        /* Send the RHE message */
        retval = sendRHEMessage(bpm->sc.server, connectionId, cm);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "TCP %lu\t| Could not send the RHE message "
                           "with status %s",
                           (unsigned long)context->currentConnection.connectionId,
                           UA_StatusCode_name(retval));
            cm->closeConnection(cm, connectionId);
            return;
        }

        context->channel->state = UA_SECURECHANNELSTATE_RHE_SENT;
        setReverseConnectState(bpm->sc.server, context, UA_SECURECHANNELSTATE_RHE_SENT);
        return;
    }

    UA_EventLoop *el = bpm->sc.server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);

    /* The connection is fully opened and we have a SecureChannel.
     * Process the received buffer */
    retval = UA_SecureChannel_loadBuffer(context->channel, msg);
    while(UA_LIKELY(retval == UA_STATUSCODE_GOOD)) {
        UA_MessageType messageType;
        UA_UInt32 requestId = 0;
        UA_ByteString payload = UA_BYTESTRING_NULL;
        UA_Boolean copied = false;
        retval = UA_SecureChannel_getCompleteMessage(context->channel, &messageType,
                                                     &requestId, &payload, &copied, nowMonotonic);
        if(retval != UA_STATUSCODE_GOOD || payload.length == 0)
            break;
        retval = processSecureChannelMessage(bpm->sc.server, context->channel,
                                             messageType, requestId, &payload);
        if(copied)
            UA_ByteString_clear(&payload);
    }
    retval |= UA_SecureChannel_persistBuffer(context->channel);

    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(bpm->logging, context->channel,
                               "Processing the message failed with error %s",
                               UA_StatusCode_name(retval));

        /* Processing the buffer failed within the SecureChannel.
         * Send an ERR message and close the connection. */
        UA_TcpErrorMessage error;
        error.error = retval;
        error.reason = UA_STRING_NULL;
        UA_SecureChannel_sendERR(context->channel, &error);
        UA_SecureChannel_shutdown(context->channel, UA_SHUTDOWNREASON_ABORT);
        setReverseConnectState(bpm->sc.server, context, UA_SECURECHANNELSTATE_CLOSING);
        return;
    }

    /* Update the state with the current SecureChannel state */
    setReverseConnectState(bpm->sc.server, context, context->channel->state);
}

void
serverReverseConnectCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                             void *application, void **connectionContext,
                             UA_ConnectionState state, const UA_KeyValueMap *params,
                             UA_ByteString msg) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)application;
    lockServer(bpm->sc.server);
    serverReverseConnectCallbackLocked(cm, connectionId, application, connectionContext,
                                       state, params, msg);
    unlockServer(bpm->sc.server);
}

/***************************/
/* Binary Protocol Manager */
/***************************/

static UA_StatusCode
UA_BinaryProtocolManager_start(UA_ServerComponent *sc, UA_Server *server) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)sc;

    UA_ServerConfig *config = &server->config;
    
    UA_StatusCode retVal =
        addRepeatedCallback(server, secureChannelHouseKeeping,
                            bpm, 1000.0, &bpm->houseKeepingCallbackId);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    /* Open server sockets */
    UA_Boolean haveServerSocket = false;
    if(config->serverUrlsSize == 0) {
        /* Empty hostname -> listen on all devices */
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "No Server URL configured. Using \"opc.tcp://:4840\" "
                       "to configure the listen socket.");
        UA_String defaultUrl = UA_STRING("opc.tcp://:4840");
        retVal = createServerConnection(bpm, &defaultUrl);
        if(retVal == UA_STATUSCODE_GOOD)
            haveServerSocket = true;
    } else {
        for(size_t i = 0; i < config->serverUrlsSize; i++) {
            retVal = createServerConnection(bpm, &config->serverUrls[i]);
            if(retVal == UA_STATUSCODE_GOOD)
                haveServerSocket = true;
        }
    }

    if(!haveServerSocket) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                     "The server has no server socket");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Update the application description to include the server urls for
     * discovery. Don't add the urls with an empty host (listening on all
     * interfaces) */
    for(size_t i = 0; i < config->serverUrlsSize; i++) {
        UA_String hostname = UA_STRING_NULL;
        UA_String path = UA_STRING_NULL;
        UA_UInt16 port = 0;
        retVal = UA_parseEndpointUrl(&config->serverUrls[i],
                                     &hostname, &port, &path);
        if(retVal != UA_STATUSCODE_GOOD || hostname.length == 0)
            continue;

        /* Check if the ServerUrl is already present in the DiscoveryUrl array.
         * Add if not already there. */
        size_t j = 0;
        for(; j < config->applicationDescription.discoveryUrlsSize; j++) {
            if(UA_String_equal(&config->serverUrls[i],
                               &config->applicationDescription.discoveryUrls[j]))
                break;
        }
        if(j == config->applicationDescription.discoveryUrlsSize) {
            retVal =
                UA_Array_appendCopy((void**)&config->applicationDescription.discoveryUrls,
                                    &config->applicationDescription.discoveryUrlsSize,
                                    &config->serverUrls[i], &UA_TYPES[UA_TYPES_STRING]);
            (void)retVal;
        }
    }

    /* Set the state to started */
    setBinaryProtocolManagerState(bpm, UA_LIFECYCLESTATE_STARTED);

    return UA_STATUSCODE_GOOD;
}

static void
UA_BinaryProtocolManager_stop(UA_ServerComponent *comp) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)comp;

    /* Stop the Housekeeping Task */
    removeCallback(bpm->sc.server, bpm->houseKeepingCallbackId);
    bpm->houseKeepingCallbackId = 0;

    /* Stop the regular retry callback */
    setReverseConnectRetryCallback(bpm, false);

    /* Close or free all reverse connections */
    reverse_connect_context *rev, *rev_tmp;
    LIST_FOREACH_SAFE(rev, &bpm->reverseConnects, next, rev_tmp) {
        if(rev->currentConnection.connectionId) {
            UA_ConnectionManager *cm = rev->currentConnection.connectionManager;
            rev->destruction = true;
            cm->closeConnection(cm, rev->currentConnection.connectionId);
        } else {
            LIST_REMOVE(rev, next);
            setReverseConnectState(bpm->sc.server, rev, UA_SECURECHANNELSTATE_CLOSED);
            UA_String_clear(&rev->hostname);
            UA_free(rev);
        }
    }

    /* Stop all SecureChannels */
    UA_SecureChannel *channel;
    TAILQ_FOREACH(channel, &bpm->channels, componentEntry) {
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
    }

    /* Stop all server sockets */
    for(size_t i = 0; i < UA_MAXSERVERCONNECTIONS; i++) {
        UA_ServerConnection *sc = &bpm->serverConnections[i];
        UA_ConnectionManager *cm = sc->connectionManager;
        if(sc->connectionId > 0)
            cm->closeConnection(cm, sc->connectionId);
    }

    /* If open sockets remain, set to STOPPING */
    if(bpm->serverConnectionsSize == 0 &&
       LIST_EMPTY(&bpm->reverseConnects) &&
       TAILQ_EMPTY(&bpm->channels)) {
        setBinaryProtocolManagerState(bpm, UA_LIFECYCLESTATE_STOPPED);
    } else {
        setBinaryProtocolManagerState(bpm, UA_LIFECYCLESTATE_STOPPING);
    }
}

static UA_StatusCode
UA_BinaryProtocolManager_clear(UA_ServerComponent *sc) {
    if(sc->state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_ERROR(sc->server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Cannot delete the BinaryProtocolManager because "
                     "it is not stopped");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

UA_ServerComponent *
UA_BinaryProtocolManager_new(UA_Server *server) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)
        UA_calloc(1, sizeof(UA_BinaryProtocolManager));
    if(!bpm)
        return NULL;

    TAILQ_INIT(&bpm->channels);

    bpm->sc.name = UA_STRING("binary");
    bpm->sc.start = UA_BinaryProtocolManager_start;
    bpm->sc.stop = UA_BinaryProtocolManager_stop;
    bpm->sc.clear = UA_BinaryProtocolManager_clear;

    bpm->sc.server = server;
    bpm->logging = server->config.logging;

    return &bpm->sc;
}

/**** amalgamated original file "/src/server/ua_server_utils.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 */


/****************************/
/* Custom DataType Handling */
/****************************/

const UA_DataTypeArray *
serverCustomTypes(UA_Server *server) {
    if(server->customTypes_internalSize == 0)
        return server->config.customDataTypes;
    server->customTypes_internal[server->customTypes_internalSize-1].next = server->config.customDataTypes;
    return server->customTypes_internal;
}

const UA_DataTypeArray *
UA_Server_getDataTypes(UA_Server *server) {
    lockServer(server);
    const UA_DataTypeArray * out = serverCustomTypes(server);
    unlockServer(server);
    return out;
}

const UA_DataType *
UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId) {
    return UA_findDataTypeWithCustom(typeId, serverCustomTypes(server));
}

/* DataTypes need a stable pointer. So we allocate an array of 64 datatypes.
 * When that is full we move the server->customTypes_internal into a
 * heap-structure that gets cleaned up with the server lifecycle. */
static UA_StatusCode
addDataType(UA_Server *server, UA_DataType *dt) {
    /* Allocate the space for the new DataType */
#define TYPES_LIST_SIZE 64
    UA_DataTypeArray *current = NULL;
    if(server->customTypes_internalSize > 0)
        current = &server->customTypes_internal[server->customTypes_internalSize-1];
    if(!current || current->typesSize == TYPES_LIST_SIZE) {
        /* Increase the list-of-lists size */
        UA_DataTypeArray *lol = (UA_DataTypeArray*)
            UA_realloc(server->customTypes_internal,
                       sizeof(UA_DataTypeArray) * (server->customTypes_internalSize+1));
        if(!lol)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        memset(&lol[server->customTypes_internalSize], 0, sizeof(UA_DataTypeArray));
        server->customTypes_internal = lol;
        server->customTypes_internalSize++;

        /* Update the next-pointers for the internal DataTypeArray */
        for(size_t i = 0; i < server->customTypes_internalSize-1; i++)
            lol[i].next = &lol[i+1];

        /* Add a new types list. With the space for the datatypes already appended */
        current = &server->customTypes_internal[server->customTypes_internalSize-1];
        current->types = (UA_DataType*)UA_calloc(TYPES_LIST_SIZE, sizeof(UA_DataType));
        current->typesSize = 0;
        if(!current->types) {
            server->customTypes_internalSize--;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
    }

    /* Move the datatype into the stable location in the server */
    current->types[current->typesSize] = *dt;
    current->typesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_addDataType(UA_Server *server, const UA_NodeId parentNodeId,
                      const UA_DataType *type) {
    /* Check that the type does not already exist. We do not allow changes to
     * DataTypes once they are set. */
    if(UA_Server_findDataType(server, &type->typeId))
        return UA_STATUSCODE_BADNODEIDEXISTS;

    /* Make a copy of the UA_DataType */
    UA_DataType dt2;
    UA_StatusCode res = UA_DataType_copy(type, &dt2);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Add the UA_DataType to the server */
    res = addDataType(server, &dt2);
    if(res != UA_STATUSCODE_GOOD)
        UA_DataType_clear(&dt2);
    return res;
}

UA_StatusCode
UA_Server_addDataTypeFromDescription(UA_Server *server,
                                     const UA_ExtensionObject *description) {
    /* Translate into a new UA_DataType */
    UA_DataType dt;
    UA_StatusCode res =
        UA_DataType_fromDescription(&dt, description, serverCustomTypes(server));
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Check that the type does not already exist. We do not allow changes to
     * DataTypes once they are set. */
    if(UA_Server_findDataType(server, &dt.typeId)) {
        UA_DataType_clear(&dt);
        return UA_STATUSCODE_BADNODEIDEXISTS;
    }

    /* Add the UA_DataType to the server */
    res = addDataType(server, &dt);
    if(res != UA_STATUSCODE_GOOD)
        UA_DataType_clear(&dt);
    return res;
}

/********************************/
/* Information Model Operations */
/********************************/

struct ReturnTypeContext {
    UA_Server *server;
    UA_UInt32 attributeMask;
    UA_ReferenceTypeSet references;
    UA_BrowseDirection referenceDirections;
};

static void *
returnFirstType(void *context, UA_ReferenceTarget *t) {
    struct ReturnTypeContext *ctx = (struct ReturnTypeContext*)context;
    /* Don't release the node that is returned.
     * Continues to iterate if NULL is returned. */
    return (void *)(uintptr_t)UA_NODESTORE_GETFROMREF_SELECTIVE(
        ctx->server, t->targetId, ctx->attributeMask, ctx->references,
        ctx->referenceDirections);
}

const UA_Node *
getNodeType(UA_Server *server, const UA_NodeHead *head,
            UA_UInt32 attributeMask, UA_ReferenceTypeSet references,
            UA_BrowseDirection referenceDirections) {
    /* The reference to the parent is different for variable and variabletype */
    UA_Byte parentRefIndex;
    UA_Boolean inverse;
    switch(head->nodeClass) {
    case UA_NODECLASS_OBJECT:
    case UA_NODECLASS_VARIABLE:
        parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION;
        inverse = false;
        break;
    case UA_NODECLASS_OBJECTTYPE:
    case UA_NODECLASS_VARIABLETYPE:
    case UA_NODECLASS_REFERENCETYPE:
    case UA_NODECLASS_DATATYPE:
        parentRefIndex = UA_REFERENCETYPEINDEX_HASSUBTYPE;
        inverse = true;
        break;
    default:
        return NULL;
    }

    struct ReturnTypeContext ctx;
    ctx.server = server;
    ctx.attributeMask = attributeMask;
    ctx.references = references;
    ctx.referenceDirections = referenceDirections;

    /* Return the first matching candidate */
    for(size_t i = 0; i < head->referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(rk->isInverse != inverse)
            continue;
        if(rk->referenceTypeIndex != parentRefIndex)
            continue;
        const UA_Node *type = (const UA_Node*)
            UA_NodeReferenceKind_iterate(rk, returnFirstType, &ctx);
        if(type)
            return type;
    }

    return NULL;
}

UA_Boolean
UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head) {
    for(size_t i = 0; i < head->referencesSize; ++i) {
        if(head->references[i].isInverse == false &&
           head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASSUBTYPE)
            return true;
        if(head->references[i].isInverse == true &&
           head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASTYPEDEFINITION)
            return true;
    }
    return false;
}

UA_StatusCode
getTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *leafNode,
                             UA_Boolean includeLeaf, UA_NodeId **typeHierarchy,
                             size_t *typeHierarchySize) {
    UA_ReferenceTypeSet hastype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASTYPEDEFINITION);
    UA_ReferenceTypeSet hassubtype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
    UA_ReferenceTypeSet hasinterface = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE);

    /* Initialize the tree and add the leaf */
    RefTree rt;
    UA_StatusCode res = RefTree_init(&rt);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    res = RefTree_addNodeId(&rt, leafNode, NULL);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Get all types */
    res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hastype,
                                 UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Get all super types */
    res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_INVERSE, &hassubtype,
                                 UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Get all interfaces */
    res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hasinterface,
                                 UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE);

 errout:
    if(res != UA_STATUSCODE_GOOD || rt.size == 0) {
        RefTree_clear(&rt);
        return res;
    }

    /* Make the array of ExpandedNodeId into an array of NodeId */
    UA_NodeId *outArray = (UA_NodeId*)rt.targets;
    size_t pos = 0;
    for(size_t i = 0; i < rt.size; i++) {
        UA_NodeId *n = &outArray[pos];
        UA_ExpandedNodeId *e = &rt.targets[i];
        if(!UA_ExpandedNodeId_isLocal(e)) {
            UA_ExpandedNodeId_clear(e);
            continue;
        }
        *n = e->nodeId;
        UA_String_clear(&e->namespaceUri);
        pos++;
    }

    *typeHierarchySize = pos;
    *typeHierarchy = outArray;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
getAllInterfaces(UA_Server *server, const UA_NodeId *objectNode,
                 UA_NodeId **interfaceNodes, size_t *interfaceNodesSize) {
    UA_ReferenceTypeSet hastype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASTYPEDEFINITION);
    UA_ReferenceTypeSet hassubtype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
    UA_ReferenceTypeSet hasinterface = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE);

    /* Initialize the tree and add the leaf */
    size_t beforeInterfaces = 0;
    RefTree rt;
    UA_StatusCode res = RefTree_init(&rt);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    res = RefTree_addNodeId(&rt, objectNode, NULL);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Get all types */
    res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hastype,
                                 UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Get all super types */
    res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_INVERSE, &hassubtype,
                                 UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Get all interfaces */
    beforeInterfaces = rt.size; /* Return only the interfaces */
    res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hasinterface,
                                 UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE);

 errout:
    if(res != UA_STATUSCODE_GOOD || rt.size == 0) {
        RefTree_clear(&rt);
        return res;
    }

    /* Make the array of ExpandedNodeId into an array of NodeId */
    UA_NodeId *outArray = (UA_NodeId*)rt.targets;
    size_t pos = 0;
    for(size_t i = 0; i < rt.size; i++) {
        UA_NodeId *n = &outArray[pos];
        UA_ExpandedNodeId *e = &rt.targets[i];
        if(i < beforeInterfaces || !UA_ExpandedNodeId_isLocal(e)) {
            UA_ExpandedNodeId_clear(e);
            continue;
        }
        *n = e->nodeId;
        UA_String_clear(&e->namespaceUri);
        pos++;
    }

    /* No interfaces found */
    if(pos == 0) {
        RefTree_clear(&rt);
        outArray = NULL;
    }

    *interfaceNodesSize = pos;
    *interfaceNodes = outArray;
    return UA_STATUSCODE_GOOD;
}

/* Get the node, make the changes and release */
UA_StatusCode
editNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
         UA_UInt32 attributeMask, UA_ReferenceTypeSet references,
         UA_BrowseDirection referenceDirections,
         UA_EditNodeCallback callback, void *data) {
    UA_Node *node =
        UA_NODESTORE_GET_EDIT_SELECTIVE(server, nodeId, attributeMask,
                                        references, referenceDirections);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    UA_StatusCode retval = callback(server, session, node, data);
    UA_NODESTORE_RELEASE(server, node);
    return retval;
}

/**************************/
/* Certificate Validation */
/**************************/

UA_StatusCode
validateCertificate(UA_Server *server, UA_CertificateGroup *cg,
                    UA_SecureChannel *channel, UA_Session *session,
                    const char *logPrefix,
                    const UA_ApplicationDescription *ad,
                    const UA_ByteString certificate) {
    /* Verify the ApplicationUri */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ad) {
        res = UA_CertificateUtils_verifyApplicationUri(&certificate,
                                                       &ad->applicationUri);
        if(res != UA_STATUSCODE_GOOD) {
            if(server->config.allowAllCertificateUris <= UA_RULEHANDLING_WARN) {
                if(session) {
                    UA_LOG_ERROR_SESSION(server->config.logging, session,
                                         "%s: The client's ApplicationUri "
                                         "could not be verified against the "
                                         "ApplicationUri %S from the client's "
                                         "ApplicationDescription", logPrefix,
                                         ad->applicationUri);
                } else if(channel) {
                    UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                                         "%s: The client certificate's ApplicationUri "
                                         "could not be verified against the "
                                         "ApplicationUri %S from the client's "
                                         "ApplicationDescription", logPrefix,
                                         ad->applicationUri);
                } else {
                    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "%s: The server certificate's ApplicationUri "
                                 "could not be verified against the "
                                 "ApplicationUri %S from its "
                                 "ApplicationDescription", logPrefix,
                                 ad->applicationUri);
                }
            }
            if(server->config.allowAllCertificateUris <= UA_RULEHANDLING_ABORT)
                return UA_STATUSCODE_BADCERTIFICATEINVALID;
        }
    }

    if(!cg->verifyCertificate) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "%s: Could not validate the certificate "
                     "as the CertificateGroup is not configured", logPrefix);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Validate in the CertificateGroup */
    res = cg->verifyCertificate(cg, &certificate);
    if(res != UA_STATUSCODE_GOOD) {
        const char *descr = UA_StatusCode_name(res);
        if(session) {
            UA_LOG_ERROR_SESSION(server->config.logging, session,
                                 "%s: The client certificate failed the verification "
                                 "in the CertificateGroup with StatusCode %s",
                                 logPrefix, descr);
        } else if(channel) {
            UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                                 "%s: The client certificate failed the verification "
                                 "in the CertificateGroup with StatusCode %s",
                                 logPrefix, descr);
        } else {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "%s: The client certificate failed the verification "
                         "in the CertificateGroup with StatusCode %s",
                         logPrefix, descr);
        }
    }
    return res;
}

/*********************************/
/* Default attribute definitions */
/*********************************/

const UA_ObjectAttributes UA_ObjectAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    0                       /* eventNotifier */
};

const UA_VariableAttributes UA_VariableAttributes_default = {
    0,                           /* specifiedAttributes */
    {{0, NULL}, {0, NULL}},      /* displayName */
    {{0, NULL}, {0, NULL}},      /* description */
    0, 0,                        /* writeMask (userWriteMask) */
    {NULL, UA_VARIANT_DATA,
     0, NULL, 0, NULL},          /* value */
    {0, UA_NODEIDTYPE_NUMERIC,
     {UA_NS0ID_BASEDATATYPE}},   /* dataType */
    UA_VALUERANK_ANY,            /* valueRank */
    0, NULL,                     /* arrayDimensions */
    UA_ACCESSLEVELMASK_READ |    /* accessLevel */
    UA_ACCESSLEVELMASK_STATUSWRITE |
    UA_ACCESSLEVELMASK_TIMESTAMPWRITE,
    0,                           /* userAccessLevel */
    0.0,                         /* minimumSamplingInterval */
    false                        /* historizing */
};

const UA_MethodAttributes UA_MethodAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    true, true              /* executable (userExecutable) */
};

const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false                   /* isAbstract */
};

const UA_VariableTypeAttributes UA_VariableTypeAttributes_default = {
    0,                           /* specifiedAttributes */
    {{0, NULL}, {0, NULL}},      /* displayName */
    {{0, NULL}, {0, NULL}},      /* description */
    0, 0,                        /* writeMask (userWriteMask) */
    {NULL, UA_VARIANT_DATA,
     0, NULL, 0, NULL},          /* value */
    {0, UA_NODEIDTYPE_NUMERIC,
     {UA_NS0ID_BASEDATATYPE}},   /* dataType */
    UA_VALUERANK_ANY,            /* valueRank */
    0, NULL,                     /* arrayDimensions */
    false                        /* isAbstract */
};

const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false,                  /* isAbstract */
    false,                  /* symmetric */
    {{0, NULL}, {0, NULL}}  /* inverseName */
};

const UA_DataTypeAttributes UA_DataTypeAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false                   /* isAbstract */
};

const UA_ViewAttributes UA_ViewAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false,                  /* containsNoLoops */
    0                       /* eventNotifier */
};


/**** amalgamated original file "/src/server/ua_server_async.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick)
 *    Copyright 2019, 2025 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


/* The layout of the results array is is:
 * [results-array] | padding | UA_AsyncResponse | padding | [UA_AsyncOperation]
 *
 * We need to take care about memory alignment (padding). */
static void *
allocateResultsArray(const UA_DataType *resultsType, size_t resultsLen,
                     UA_AsyncResponse **resp, UA_AsyncOperation **ops) {
    uintptr_t align = sizeof(size_t);
    size_t arrEnd = resultsType->memSize * resultsLen;
    uintptr_t responseBegin = (arrEnd + align - 1) & ~(align - 1);
    uintptr_t responseEnd = responseBegin + sizeof(UA_AsyncResponse);
    uintptr_t opsBegin = (responseEnd + align - 1) & ~(align - 1);
    uintptr_t opsEnd =  opsBegin + (sizeof(UA_AsyncOperation) * resultsLen);
    void *arr = UA_calloc(1, opsEnd);
    if(!arr)
        return NULL;
    uintptr_t arrMem = (uintptr_t)arr;
    *resp = (UA_AsyncResponse*)(arrMem + responseBegin);
    *ops = (UA_AsyncOperation*)(arrMem + opsBegin);
    return arr;
}

/* Cancel the operation, but don't _clear it here */
static void
UA_AsyncOperation_cancel(UA_Server *server, UA_AsyncOperation *op,
                         UA_StatusCode opstatus) {
    UA_ServerConfig *sc = &server->config;
    void *cancelPtr = NULL;

    /* Set the status and get the pointer that identifies the operation */
    switch(op->asyncOperationType) {
    case UA_ASYNCOPERATIONTYPE_READ_REQUEST:
        cancelPtr = op->output.read;
        op->output.read->hasStatus = true;
        op->output.read->status = opstatus;
        break;
    case UA_ASYNCOPERATIONTYPE_READ_DIRECT:
        cancelPtr = &op->output.directRead;
        op->output.directRead.hasStatus = true;
        op->output.directRead.status = opstatus;
        break;
    case UA_ASYNCOPERATIONTYPE_WRITE_REQUEST:
        cancelPtr = &op->context.writeValue.value;
        *op->output.write = opstatus;
        break;
    case UA_ASYNCOPERATIONTYPE_WRITE_DIRECT:
        cancelPtr = &op->context.writeValue.value;
        op->output.directWrite = opstatus;
        break;
    case UA_ASYNCOPERATIONTYPE_CALL_REQUEST:
        /* outputArguments is always an allocated pointer, also if the length is zero */
        cancelPtr = op->output.call->outputArguments;
        op->output.call->statusCode = opstatus;
        break;
    case UA_ASYNCOPERATIONTYPE_CALL_DIRECT:
        /* outputArguments is always an allocated pointer, also if the length is zero */
        cancelPtr = op->output.directCall.outputArguments;
        op->output.directCall.statusCode = opstatus;
        break;
    default: UA_assert(false); return;
    }

    /* Notify the application that it must no longer set the async result */
    if(sc->asyncOperationCancelCallback)
        sc->asyncOperationCancelCallback(server, cancelPtr);
}

static void
UA_AsyncOperation_delete(UA_AsyncOperation *op) {
    UA_assert(op->asyncOperationType >= UA_ASYNCOPERATIONTYPE_CALL_DIRECT);
    switch(op->asyncOperationType) {
    case UA_ASYNCOPERATIONTYPE_READ_DIRECT:
        UA_DataValue_clear(&op->output.directRead);
        break;
    case UA_ASYNCOPERATIONTYPE_WRITE_DIRECT:
        break;
    case UA_ASYNCOPERATIONTYPE_CALL_DIRECT:
        UA_CallMethodResult_clear(&op->output.directCall);
        break;
    default: UA_assert(false); break;
    }
    UA_free(op);
}

static void
UA_AsyncResponse_delete(UA_AsyncResponse *ar) {
    UA_NodeId_clear(&ar->sessionId);

    /* Clean up the results array last. Because the results array memory also
     * includes ar. */
    void *arr = NULL;
    size_t arrSize = 0;
    const UA_DataType *arrType;
    if(ar->responseType == &UA_TYPES[UA_TYPES_CALLRESPONSE]) {
        arr = ar->response.callResponse.results;
        arrSize = ar->response.callResponse.resultsSize;
        ar->response.callResponse.results = NULL;
        ar->response.callResponse.resultsSize = 0;
        arrType = &UA_TYPES[UA_TYPES_CALLMETHODRESULT];
    } else if(ar->responseType == &UA_TYPES[UA_TYPES_READRESPONSE]) {
        arr = ar->response.readResponse.results;
        arrSize = ar->response.readResponse.resultsSize;
        ar->response.readResponse.results = NULL;
        ar->response.readResponse.resultsSize = 0;
        arrType = &UA_TYPES[UA_TYPES_DATAVALUE];
    } else /* if(ar->responseType == &UA_TYPES[UA_TYPES_WRITERESPONSE]) */ {
        UA_assert(ar->responseType == &UA_TYPES[UA_TYPES_WRITERESPONSE]);
        arr = ar->response.writeResponse.results;
        arrSize = ar->response.writeResponse.resultsSize;
        ar->response.writeResponse.results = NULL;
        ar->response.writeResponse.resultsSize = 0;
        arrType = &UA_TYPES[UA_TYPES_STATUSCODE];
    }
    UA_clear(&ar->response.callResponse, ar->responseType);
    UA_Array_delete(arr, arrSize, arrType);
}

static void
notifyServiceEnd(UA_Server *server, UA_AsyncResponse *ar,
                 UA_Session *session, UA_SecureChannel *sc) {
    /* Nothing to do? */
    UA_ServerConfig *config = UA_Server_getConfig(server);
    if(!config->globalNotificationCallback && !config->serviceNotificationCallback)
        return;

    /* Collect the payload */
    UA_NodeId sessionId = (session) ? session->sessionId : UA_NODEID_NULL;
    UA_UInt32 secureChannelId = (sc) ? sc->securityToken.channelId : 0;
    UA_NodeId serviceTypeId;
    if(ar->responseType == &UA_TYPES[UA_TYPES_CALLRESPONSE]) {
        serviceTypeId = UA_TYPES[UA_TYPES_CALLREQUEST].typeId;
    } else if(ar->responseType == &UA_TYPES[UA_TYPES_READRESPONSE]) {
        serviceTypeId = UA_TYPES[UA_TYPES_READREQUEST].typeId;
    } else /* if(ar->responseType == &UA_TYPES[UA_TYPES_WRITERESPONSE]) */ {
        serviceTypeId = UA_TYPES[UA_TYPES_WRITEREQUEST].typeId;
    }

    /* Notify the application */
    static UA_THREAD_LOCAL UA_KeyValuePair notifyPayload[4] = {
        {{0, UA_STRING_STATIC("securechannel-id")}, {0}},
        {{0, UA_STRING_STATIC("session-id")}, {0}},
        {{0, UA_STRING_STATIC("request-id")}, {0}},
        {{0, UA_STRING_STATIC("service-type")}, {0}}
    };
    UA_KeyValueMap notifyPayloadMap = {4, notifyPayload};
    if(config->serviceNotificationCallback || config->globalNotificationCallback) {
        UA_Variant_setScalar(&notifyPayload[0].value, &secureChannelId,
                             &UA_TYPES[UA_TYPES_UINT32]);
        UA_Variant_setScalar(&notifyPayload[1].value, &sessionId,
                             &UA_TYPES[UA_TYPES_NODEID]);
        UA_Variant_setScalar(&notifyPayload[2].value, &ar->requestId,
                             &UA_TYPES[UA_TYPES_UINT32]);
        UA_Variant_setScalar(&notifyPayload[3].value, &serviceTypeId,
                             &UA_TYPES[UA_TYPES_NODEID]);
    }

    UA_ApplicationNotificationType nt = UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_END;
    if(config->serviceNotificationCallback)
        config->serviceNotificationCallback(server, nt, notifyPayloadMap);
    if(config->globalNotificationCallback)
        config->globalNotificationCallback(server, nt, notifyPayloadMap);
}

static void
sendAsyncResponse(UA_Server *server, UA_AsyncResponse *ar) {
    UA_assert(ar->opCountdown == 0);

    /* Get the session */
    UA_Session *session = getSessionById(server, &ar->sessionId);
    UA_SecureChannel *channel = (session) ? session->channel : NULL;

    /* Notify that processing the service has ended */
    notifyServiceEnd(server, ar, session, channel);

    /* Check the session */
    if(!session) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Async Service: Session %N no longer exists", ar->sessionId);
        return;
    }

    /* Check the channel */
    if(!channel) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Async Service Response cannot be sent. "
                               "No SecureChannel for the session.");
        return;
    }

    /* Set the request handle */
    UA_ResponseHeader *responseHeader = (UA_ResponseHeader*)
        &ar->response.callResponse.responseHeader;
    responseHeader->requestHandle = ar->requestHandle;

    /* Send the Response */
    UA_StatusCode res = sendResponse(server, channel, ar->requestId,
                                     (UA_Response*)&ar->response, ar->responseType);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Async Response for Req# %" PRIu32 " failed "
                               "with StatusCode %s", ar->requestId,
                               UA_StatusCode_name(res));
    }
}

static void
directOpCallback(UA_Server *server, UA_AsyncOperation *op) {
    switch(op->asyncOperationType) {
    case UA_ASYNCOPERATIONTYPE_READ_DIRECT:
        op->handling.callback.method.read(server,
                                          op->handling.callback.context,
                                          &op->output.directRead);
        break;
    case UA_ASYNCOPERATIONTYPE_WRITE_DIRECT:
        op->handling.callback.method.write(server,
                                           op->handling.callback.context,
                                           op->output.directWrite);
        break;
    case UA_ASYNCOPERATIONTYPE_CALL_DIRECT:
        op->handling.callback.method.call(server,
                                          op->handling.callback.context,
                                          &op->output.directCall);
        break;
    default: UA_assert(false); break;
    }
}

/* Called from the EventLoop via a delayed callback */
static void
UA_AsyncManager_processReady(UA_Server *server, UA_AsyncManager *am) {
    lockServer(server);

    /* Reset the delayed callback */
    UA_atomic_xchg((void**)&am->dc.callback, NULL);

    /* Process ready direct operations and free them */
    UA_AsyncOperation *op = NULL, *op_tmp = NULL;
    TAILQ_FOREACH_SAFE(op, &am->readyOps, pointers, op_tmp) {
        TAILQ_REMOVE(&am->readyOps, op, pointers);
        am->opsCount--;
        directOpCallback(server, op);
        UA_AsyncOperation_delete(op);
    }

    /* Send out ready responses */
    UA_AsyncResponse *ar, *temp;
    TAILQ_FOREACH_SAFE(ar, &am->readyResponses, pointers, temp) {
        TAILQ_REMOVE(&am->readyResponses, ar, pointers);
        sendAsyncResponse(server, ar);
        UA_AsyncResponse_delete(ar);
    }

    unlockServer(server);
}

static void
processOperationResult(UA_Server *server, UA_AsyncOperation *op) {
    UA_AsyncManager *am = &server->asyncManager;
    if(op->asyncOperationType >= UA_ASYNCOPERATIONTYPE_CALL_DIRECT) {
        /* Direct operation */
        TAILQ_REMOVE(&am->waitingOps, op, pointers);
        TAILQ_INSERT_TAIL(&am->readyOps, op, pointers);
    } else {
        /* Part of a service request */
        TAILQ_REMOVE(&am->waitingOps, op, pointers);
        am->opsCount--;

        UA_AsyncResponse *ar = op->handling.response;
        ar->opCountdown -= 1;
        if(ar->opCountdown > 0)
            return;

        /* Enqueue ar in the readyResponses */
        TAILQ_REMOVE(&am->waitingResponses, ar, pointers);
        TAILQ_INSERT_TAIL(&am->readyResponses, ar, pointers);
    }

    /* Trigger the main server thread to handle ready operations and responses */
    if(am->dc.callback == NULL) {
        UA_EventLoop *el = server->config.eventLoop;
        am->dc.callback = (UA_Callback)UA_AsyncManager_processReady;
        am->dc.application = server;
        am->dc.context = am;
        el->addDelayedCallback(el, &am->dc);
        el->cancel(el); /* Wake up the EventLoop if currently waiting in select() */
    }
}

/* Check if any operations have timed out */
static void
checkTimeouts(UA_Server *server, void *_) {
    /* Timeouts are not configured */
    if(server->config.asyncOperationTimeout <= 0.0)
        return;

    lockServer(server);

    UA_EventLoop *el = server->config.eventLoop;
    UA_AsyncManager *am = &server->asyncManager;
    const UA_DateTime tNow = el->dateTime_nowMonotonic(el);

    /* Loop over the waiting ops */
    UA_AsyncOperation *op = NULL, *op_tmp = NULL;
    TAILQ_FOREACH_SAFE(op, &am->waitingOps, pointers, op_tmp) {
        /* Check the timeout */
        if(op->asyncOperationType <= UA_ASYNCOPERATIONTYPE_WRITE_REQUEST) {
            if(tNow <= op->handling.response->timeout)
                continue;
        } else {
            if(tNow <= op->handling.callback.timeout)
                continue;
        }

        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Operation was removed due to a timeout");

        /* Mark operation as timed out integrate */
        UA_AsyncOperation_cancel(server, op, UA_STATUSCODE_BADTIMEOUT);
        processOperationResult(server, op);
    }

    unlockServer(server);
}

void
UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server) {
    memset(am, 0, sizeof(UA_AsyncManager));
    TAILQ_INIT(&am->waitingResponses);
    TAILQ_INIT(&am->readyResponses);
    TAILQ_INIT(&am->waitingOps);
    TAILQ_INIT(&am->readyOps);
}

void UA_AsyncManager_start(UA_AsyncManager *am, UA_Server *server) {
    /* Add a regular callback for cleanup and sending finished responses at a
     * 1s interval. */
    UA_StatusCode res = addRepeatedCallback(server, (UA_ServerCallback)checkTimeouts,
                    NULL, 1000.0, &am->checkTimeoutCallbackId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Failed to register async timeout callback. "
                    "Async operations will not be cleaned up on timeout. StatusCode: %s",
                    UA_StatusCode_name(res));
        am->checkTimeoutCallbackId = 0;
    }
}

void UA_AsyncManager_stop(UA_AsyncManager *am, UA_Server *server) {
    removeCallback(server, am->checkTimeoutCallbackId);
    if(am->dc.callback) {
        UA_EventLoop *el = server->config.eventLoop;
        el->removeDelayedCallback(el, &am->dc);
    }
}

void
UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Cancel all operations. This moves all operations and responses into the
     * ready state. */
    UA_AsyncOperation *op, *op_tmp;
    TAILQ_FOREACH_SAFE(op, &am->waitingOps, pointers, op_tmp) {
        UA_AsyncOperation_cancel(server, op, UA_STATUSCODE_BADSHUTDOWN);
        processOperationResult(server, op);
    }

    /* This sends out/notifies and removes all direct operations and async requests */
    UA_AsyncManager_processReady(server, am);
    UA_assert(am->opsCount == 0);
}

UA_UInt32
UA_AsyncManager_cancel(UA_Server *server, UA_Session *session, UA_UInt32 requestHandle) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Loop over all waiting operations */
    UA_UInt32 count = 0;
    UA_AsyncOperation *op, *op_tmp;
    UA_AsyncManager *am = &server->asyncManager;
    TAILQ_FOREACH_SAFE(op, &am->waitingOps, pointers, op_tmp) {
        UA_AsyncResponse *ar = op->handling.response;
        if(ar->requestHandle != requestHandle ||
           !UA_NodeId_equal(&session->sessionId, &ar->sessionId))
            continue;

        count++; /* Found a matching request */

        /* Set the status of the overall response */
        ar->response.callResponse.responseHeader.serviceResult =
            UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT;

        /* Notify, set operation status and integrate */
        UA_AsyncOperation_cancel(server, op, UA_STATUSCODE_BADOPERATIONABANDONED);
        processOperationResult(server, op);
    }

    return count;
}

static void
persistAsyncResponse(UA_Server *server, UA_Session *session,
                     void *response, UA_AsyncResponse *ar) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_AsyncManager *am = &server->asyncManager;

    /* Pending results, attach the AsyncResponse to the AsyncManager. RequestId
     * and -Handle are set in the AsyncManager before processing the request. */
    ar->requestId = am->currentRequestId;
    ar->requestHandle = am->currentRequestHandle;
    ar->sessionId = session->sessionId;
    ar->timeout = UA_INT64_MAX;

    UA_EventLoop *el = server->config.eventLoop;
    if(server->config.asyncOperationTimeout > 0.0)
        ar->timeout = el->dateTime_nowMonotonic(el) + (UA_DateTime)
            (server->config.asyncOperationTimeout * (UA_DateTime)UA_DATETIME_MSEC);

    /* Move the response content to the AsyncResponse */
    memcpy(&ar->response, response, ar->responseType->memSize);
    UA_init(response, ar->responseType);

    /* Enqueue the ar */
    TAILQ_INSERT_TAIL(&am->waitingResponses, ar, pointers);
}

static void
persistAsyncResponseOperation(UA_Server *server, UA_AsyncOperation *op,
                              UA_AsyncOperationType opType, UA_AsyncResponse *ar,
                              void *outputPtr) {
    /* Set up the async operation */
    op->asyncOperationType = opType;
    op->handling.response = ar;
    op->output.read = (UA_DataValue*)outputPtr;

    /* Not enough resources to store the async operation */
    UA_AsyncManager *am = &server->asyncManager;
    if(server->config.maxAsyncOperationQueueSize != 0 &&
       am->opsCount >= server->config.maxAsyncOperationQueueSize) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot create async operation: Queue exceeds limit (%d).",
                       (int unsigned)server->config.maxAsyncOperationQueueSize);
        /* No need to call processOperationResult or UA_AsyncOperation_delete
         * here. The response already has the status code integrated. */
        UA_AsyncOperation_cancel(server, op, UA_STATUSCODE_BADTOOMANYOPERATIONS);
        return;
    }

    /* Enqueue the asyncop in the async manager */
    TAILQ_INSERT_TAIL(&am->waitingOps, op, pointers);
    ar->opCountdown++;
    am->opsCount++;
}

static UA_StatusCode
persistAsyncDirectOperation(UA_Server *server, UA_AsyncOperation *op,
                            UA_AsyncOperationType opType, void *context,
                            uintptr_t callback, UA_DateTime timeout) {
    /* Set up the async operation */
    op->asyncOperationType = opType;
    op->handling.callback.timeout = timeout;
    op->handling.callback.context = context;
    op->handling.callback.method.read = (UA_ServerAsyncReadResultCallback)callback;

    /* Not enough resources to store the async operation */
    UA_AsyncManager *am = &server->asyncManager;
    if(server->config.maxAsyncOperationQueueSize != 0 &&
       am->opsCount >= server->config.maxAsyncOperationQueueSize) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot create async operation: Queue exceeds limit (%d).",
                       (int unsigned)server->config.maxAsyncOperationQueueSize);
        UA_AsyncOperation_cancel(server, op, UA_STATUSCODE_BADTOOMANYOPERATIONS);
        UA_AsyncOperation_delete(op);
        return UA_STATUSCODE_BADTOOMANYOPERATIONS;
    }

    /* Enqueue the asyncop in the async manager */
    TAILQ_INSERT_TAIL(&am->waitingOps, op, pointers);
    am->opsCount++;
    return UA_STATUSCODE_GOOD;
}

void
async_cancel(UA_Server *server, void *context, UA_StatusCode opstatus,
             UA_Boolean cancelSynchronous) {
    UA_AsyncManager *am = &server->asyncManager;
    UA_AsyncOperation *op = NULL, *op_tmp = NULL;

    /* Cancel operations that are still waiting for the result */
    TAILQ_FOREACH_SAFE(op, &am->waitingOps, pointers, op_tmp) {
        if(op->handling.callback.context != context)
            continue;

        /* Cancel the operation. This sets the StatusCode and calls the
         * asyncOperationCancelCallback. */
        UA_AsyncOperation_cancel(server, op, opstatus);

        /* Call the result-callback of the local async operation.
         * Right away or in the next EventLoop iteration. */
        if(cancelSynchronous) {
            TAILQ_REMOVE(&am->waitingOps, op, pointers);
            am->opsCount--;
            directOpCallback(server, op);
            UA_AsyncOperation_delete(op);
        } else {
            processOperationResult(server, op);
        }
    }

    /* All "ready" operations get processed in the next EventLoop iteration anyway */
    if(!cancelSynchronous)
        return;

    /* Process matching ready operations synchronously and delete them */
    TAILQ_FOREACH_SAFE(op, &am->readyOps, pointers, op_tmp) {
        if(op->handling.callback.context != context)
            continue;
        TAILQ_REMOVE(&am->readyOps, op, pointers);
        am->opsCount--;
        directOpCallback(server, op);
        UA_AsyncOperation_delete(op);
    }
}

void
UA_Server_cancelAsync(UA_Server *server, void *context, UA_StatusCode opstatus,
                      UA_Boolean synchronousResultCallback) {
    lockServer(server);
    async_cancel(server, context, opstatus, synchronousResultCallback);
    unlockServer(server);
}

/********/
/* Read */
/********/

UA_Boolean
Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
             UA_ReadResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing ReadRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check if the timestampstoreturn is valid */
    if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
        return true;
    }

    /* Check if maxAge is valid */
    if(request->maxAge < 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADMAXAGEINVALID;
        return true;
    }

    /* Check if there are too many operations */
    if(server->config.maxNodesPerRead != 0 &&
       request->nodesToReadSize > server->config.maxNodesPerRead) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    /* Check if there are no operations */
    if(request->nodesToReadSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return true;
    }

    /* Allocate the results array */
    UA_AsyncResponse *ar = NULL;
    UA_AsyncOperation *aopArray = NULL;
    response->results = (UA_DataValue*)
        allocateResultsArray(&UA_TYPES[UA_TYPES_DATAVALUE],
                             request->nodesToReadSize, &ar, &aopArray);
    if(!response->results) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }
    response->resultsSize = request->nodesToReadSize;

    /* Execute the operations */
    for(size_t i = 0; i < request->nodesToReadSize; i++) {
        UA_Boolean done = Operation_Read(server, session, request->timestampsToReturn,
                                         &request->nodesToRead[i], &response->results[i]);
        if(!done)
            persistAsyncResponseOperation(server, &aopArray[i],
                                          UA_ASYNCOPERATIONTYPE_READ_REQUEST,
                                          ar, &response->results[i]);
    }

    /* If async operations are pending, persist them and signal the service is
     * not done */
    if(ar->opCountdown > 0) {
        ar->responseType = &UA_TYPES[UA_TYPES_READRESPONSE];
        persistAsyncResponse(server, session, response, ar);
    }
    return (ar->opCountdown == 0);
}

UA_StatusCode
read_async(UA_Server *server, UA_Session *session, const UA_ReadValueId *operation,
           UA_TimestampsToReturn ttr, UA_ServerAsyncReadResultCallback callback,
           void *context, UA_UInt32 timeout) {
    /* Allocate the async operation. Do this first as we need the pointer to the
     * datavalue to be stable.*/
    UA_AsyncOperation *op = (UA_AsyncOperation*)UA_calloc(1, sizeof(UA_AsyncOperation));
    if(!op)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_AsyncManager *am = &server->asyncManager;
    if(server->config.maxAsyncOperationQueueSize != 0 &&
       am->opsCount >= server->config.maxAsyncOperationQueueSize) {
        UA_free(op);
        return UA_STATUSCODE_BADTOOMANYOPERATIONS;
    }

    UA_DateTime timeoutDate = UA_INT64_MAX;
    if(timeout > 0) {
        UA_EventLoop *el = server->config.eventLoop;
        const UA_DateTime tNow = el->dateTime_nowMonotonic(el);
        timeoutDate = tNow + (timeout * UA_DATETIME_MSEC);
    }

    /* Call the operation */
    UA_Boolean done = Operation_Read(server, session, ttr, operation, &op->output.directRead);
    if(!done)
        return persistAsyncDirectOperation(server, op, UA_ASYNCOPERATIONTYPE_READ_DIRECT,
                                           context, (uintptr_t)callback, timeoutDate);

    callback(server, context, &op->output.directRead);
    UA_DataValue_clear(&op->output.directRead);
    UA_free(op);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_read_async(UA_Server *server, const UA_ReadValueId *operation,
                     UA_TimestampsToReturn ttr, UA_ServerAsyncReadResultCallback callback,
                     void *context, UA_UInt32 timeout) {
    lockServer(server);
    UA_StatusCode res = read_async(server, &server->adminSession, operation,
                                   ttr, callback, context, timeout);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_setAsyncReadResult(UA_Server *server, UA_DataValue *result) {
    lockServer(server);
    UA_AsyncManager *am = &server->asyncManager;
    UA_AsyncOperation *op = NULL;
    TAILQ_FOREACH(op, &am->waitingOps, pointers) {
        if(op->output.read == result || &op->output.directRead == result) {
            processOperationResult(server, op);
            break;
        }
    }
    unlockServer(server);
    return (op) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOTFOUND;
}

/*********/
/* Write */
/*********/

UA_Boolean
Service_Write(UA_Server *server, UA_Session *session,
              const UA_WriteRequest *request, UA_WriteResponse *response) {
    UA_assert(session != NULL);
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing WriteRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->config.maxNodesPerWrite != 0 &&
       request->nodesToWriteSize > server->config.maxNodesPerWrite) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    if(request->nodesToWriteSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return true;
    }

    /* Allocate the results array */
    UA_AsyncResponse *ar = NULL;
    UA_AsyncOperation *aopArray = NULL;
    response->results = (UA_StatusCode*)
        allocateResultsArray(&UA_TYPES[UA_TYPES_STATUSCODE],
                             request->nodesToWriteSize, &ar, &aopArray);
    if(!response->results) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }
    response->resultsSize = request->nodesToWriteSize;

    /* Execute the operations */
    for(size_t i = 0; i < request->nodesToWriteSize; i++) {
        /* Ensure a stable pointer for the writevalue. Doesn't get written to,
         * just used for the lookup of the async operation later on.
         * The original writeValue might be _clear'ed before the lookup. */
        UA_AsyncOperation *aop = &aopArray[i];
        aop->context.writeValue = request->nodesToWrite[i];
        UA_Boolean done = Operation_Write(server, session, &aop->context.writeValue,
                                          &response->results[i]);
        if(!done)
            persistAsyncResponseOperation(server, aop, UA_ASYNCOPERATIONTYPE_WRITE_REQUEST,
                                          ar, &response->results[i]);
    }

    /* If async operations are pending, persist them and signal the service is
     * not done */
    if(ar->opCountdown > 0) {
        ar->responseType = &UA_TYPES[UA_TYPES_WRITERESPONSE];
        persistAsyncResponse(server, session, response, ar);
    }
    return (ar->opCountdown == 0);
}

UA_StatusCode
write_async(UA_Server *server, UA_Session *session, const UA_WriteValue *operation,
            UA_ServerAsyncWriteResultCallback callback, void *context,
            UA_UInt32 timeout) {
    /* Allocate the async operation. Do this first as we need the pointer to the
     * datavalue to be stable.*/
    UA_AsyncOperation *op = (UA_AsyncOperation*)UA_calloc(1, sizeof(UA_AsyncOperation));
    if(!op)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_AsyncManager *am = &server->asyncManager;
    if(server->config.maxAsyncOperationQueueSize != 0 &&
       am->opsCount >= server->config.maxAsyncOperationQueueSize) {
        UA_free(op);
        return UA_STATUSCODE_BADTOOMANYOPERATIONS;
    }

    UA_DateTime timeoutDate = UA_INT64_MAX;
    if(timeout > 0) {
        UA_EventLoop *el = server->config.eventLoop;
        const UA_DateTime tNow = el->dateTime_nowMonotonic(el);
        timeoutDate = tNow + (timeout * UA_DATETIME_MSEC);
    }

    /* Call the operation */
    op->context.writeValue = *operation; /* Stable pointer */
    UA_Boolean done = Operation_Write(server, session, &op->context.writeValue,
                                      &op->output.directWrite);
    if(!done)
        return persistAsyncDirectOperation(server, op, UA_ASYNCOPERATIONTYPE_WRITE_DIRECT,
                                           context, (uintptr_t)callback, timeoutDate);

    /* Done, return right away */
    callback(server, context, op->output.directWrite);
    UA_free(op);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_write_async(UA_Server *server, const UA_WriteValue *operation,
                      UA_ServerAsyncWriteResultCallback callback,
                      void *context, UA_UInt32 timeout) {
    lockServer(server);
    UA_StatusCode res = write_async(server, &server->adminSession, operation,
                                    callback, context, timeout);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_setAsyncWriteResult(UA_Server *server,
                              const UA_DataValue *value,
                              UA_StatusCode result) {
    lockServer(server);
    UA_AsyncManager *am = &server->asyncManager;
    UA_AsyncOperation *op = NULL;
    TAILQ_FOREACH(op, &am->waitingOps, pointers) {
        if(&op->context.writeValue.value == value) {
            if(op->asyncOperationType == UA_ASYNCOPERATIONTYPE_WRITE_REQUEST)
                *op->output.write = result;
            else
                op->output.directWrite = result;
            processOperationResult(server, op);
            break;
        }
    }
    unlockServer(server);
    return (op) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOTFOUND;
}

/********/
/* Call */
/********/

#ifdef UA_ENABLE_METHODCALLS
UA_Boolean
Service_Call(UA_Server *server, UA_Session *session,
             const UA_CallRequest *request, UA_CallResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing CallRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->config.maxNodesPerMethodCall != 0 &&
        request->methodsToCallSize > server->config.maxNodesPerMethodCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    if(request->methodsToCallSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return true;
    }

    /* Allocate the results array */
    UA_AsyncResponse *ar = NULL;
    UA_AsyncOperation *aopArray = NULL;
    response->results = (UA_CallMethodResult*)
        allocateResultsArray(&UA_TYPES[UA_TYPES_CALLMETHODRESULT],
                             request->methodsToCallSize, &ar, &aopArray);
    if(!response->results) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }
    response->resultsSize = request->methodsToCallSize;

    /* Execute the operations */
    for(size_t i = 0; i < request->methodsToCallSize; i++) {
        UA_Boolean done = Operation_CallMethod(server, session, &request->methodsToCall[i],
                                               &response->results[i]);
        if(!done)
            persistAsyncResponseOperation(server, &aopArray[i],
                                          UA_ASYNCOPERATIONTYPE_CALL_REQUEST,
                                          ar, &response->results[i]);
    }

    /* If async operations are pending, persist them and signal the service is
     * not done */
    if(ar->opCountdown > 0) {
        ar->responseType = &UA_TYPES[UA_TYPES_CALLRESPONSE];
        persistAsyncResponse(server, session, response, ar);
    }
    return (ar->opCountdown == 0);
}

UA_StatusCode
call_async(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *operation,
           UA_ServerAsyncMethodResultCallback callback, void *context,
           UA_UInt32 timeout) {
    /* Allocate the async operation. Do this first as we need the pointer to the
     * datavalue to be stable.*/
    UA_AsyncOperation *op = (UA_AsyncOperation*)UA_calloc(1, sizeof(UA_AsyncOperation));
    if(!op)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_AsyncManager *am = &server->asyncManager;
    if(server->config.maxAsyncOperationQueueSize != 0 &&
       am->opsCount >= server->config.maxAsyncOperationQueueSize) {
        UA_free(op);
        return UA_STATUSCODE_BADTOOMANYOPERATIONS;
    }

    UA_DateTime timeoutDate = UA_INT64_MAX;
    if(timeout > 0) {
        UA_EventLoop *el = server->config.eventLoop;
        const UA_DateTime tNow = el->dateTime_nowMonotonic(el);
        timeoutDate = tNow + (timeout * UA_DATETIME_MSEC);
    }

    /* Call the operation */
    UA_Boolean done = Operation_CallMethod(server, session, operation,
                                           &op->output.directCall);
    if(!done)
        return persistAsyncDirectOperation(server, op, UA_ASYNCOPERATIONTYPE_CALL_DIRECT,
                                           context, (uintptr_t)callback, timeoutDate);

    /* Done, return right away */
    callback(server, context, &op->output.directCall);
    UA_CallMethodResult_clear(&op->output.directCall);
    UA_free(op);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_call_async(UA_Server *server, const UA_CallMethodRequest *operation,
                     UA_ServerAsyncMethodResultCallback callback,
                     void *context, UA_UInt32 timeout) {
    lockServer(server);
    UA_StatusCode res =
        call_async(server, &server->adminSession, operation, callback, context, timeout);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_setAsyncCallMethodResult(UA_Server *server, UA_Variant *output,
                                   UA_StatusCode result) {
    lockServer(server);
    UA_AsyncManager *am = &server->asyncManager;
    UA_AsyncOperation *op = NULL;
    TAILQ_FOREACH(op, &am->waitingOps, pointers) {
        if(op->asyncOperationType == UA_ASYNCOPERATIONTYPE_CALL_REQUEST) {
            if(op->output.call->outputArguments == output) {
                op->output.call->statusCode = result;
                processOperationResult(server, op);
                break;
            }
        } else if(op->asyncOperationType == UA_ASYNCOPERATIONTYPE_CALL_DIRECT) {
            if(op->output.directCall.outputArguments == output) {
                op->output.directCall.statusCode = result;
                processOperationResult(server, op);
                break;
            }
        }
    }
    unlockServer(server);
    return (op) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOTFOUND;
}
#endif

/**** amalgamated original file "/src/server/ua_subscription.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Joakim L. Gilje
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2017-2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020-2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

#define UA_MAX_RETRANSMISSIONQUEUESIZE 256

/****************/
/* Notification */
/****************/

static void UA_Notification_dequeueMon(UA_Notification *n);
static void UA_Notification_enqueueSub(UA_Notification *n);
static void UA_Notification_dequeueSub(UA_Notification *n);

UA_Notification *
UA_Notification_new(void) {
    UA_Notification *n = (UA_Notification*)UA_calloc(1, sizeof(UA_Notification));
    if(n) {
        /* Set the sentinel for a notification that is not enqueued a
         * subscription */
        TAILQ_NEXT(n, subEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL;
    }
    return n;
}

/* Dequeue and delete the notification */
static void
UA_Notification_delete(UA_Notification *n) {
    UA_assert(n != UA_SUBSCRIPTION_QUEUE_SENTINEL);
    UA_assert(n->mon);
    UA_Notification_dequeueMon(n);
    UA_Notification_dequeueSub(n);
    switch(n->mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        UA_EventFieldList_clear(&n->data.event);
        break;
#endif
    default:
        UA_MonitoredItemNotification_clear(&n->data.dataChange);
        break;
    }
    UA_free(n);
}

/* Add to the MonitoredItem queue, update all counters and then handle overflow */
static void
UA_Notification_enqueueMon(UA_Server *server, UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);

    /* Add to the MonitoredItem */
    TAILQ_INSERT_TAIL(&mon->queue, n, monEntry);
    ++mon->queueSize;

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(n->isOverflowEvent)
        ++mon->eventOverflows;
#endif

    /* Test for consistency */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);

    /* Ensure enough space is available in the MonitoredItem. Do this only after
     * adding the new Notification. */
    UA_MonitoredItem_ensureQueueSpace(server, mon);

    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, mon->subscription,
                              "MonitoredItem %" PRIi32 " | "
                              "Notification enqueued (Queue size %lu / %lu)",
                              mon->monitoredItemId,
                              (long unsigned)mon->queueSize,
                              (long unsigned)mon->parameters.queueSize);
}

static void
UA_Notification_enqueueSub(UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);

    UA_Subscription *sub = mon->subscription;
    UA_assert(sub);

    if(TAILQ_NEXT(n, subEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL)
        return;

    /* Add to the subscription if reporting is enabled */
    TAILQ_INSERT_TAIL(&sub->notificationQueue, n, subEntry);
    ++sub->notificationQueueSize;

    switch(mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        ++sub->eventNotifications;
        break;
#endif
    default:
        ++sub->dataChangeNotifications;
        break;
    }
}

void
UA_Notification_enqueueAndTrigger(UA_Server *server, UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_Subscription *sub = mon->subscription;
    UA_assert(sub); /* A MonitoredItem is always attached to a subscription. Can
                     * be a local MonitoredItem that gets published immediately
                     * with a callback. */

    /* If reporting or (sampled+triggered), enqueue into the Subscription first
     * and then into the MonitoredItem. UA_MonitoredItem_ensureQueueSpace
     * (called within UA_Notification_enqueueMon) assumes the notification is
     * already in the Subscription's publishing queue. */
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING ||
       (mon->monitoringMode == UA_MONITORINGMODE_SAMPLING &&
        mon->triggeredUntil > nowMonotonic)) {
        UA_Notification_enqueueSub(n);
        mon->triggeredUntil = UA_INT64_MIN;
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "Notification enqueued (Queue size %lu)",
                                  (long unsigned)sub->notificationQueueSize);
    }

    /* Insert into the MonitoredItem. This checks the queue size and
     * handles overflow. */
    UA_Notification_enqueueMon(server, n);

    for(size_t i = mon->triggeringLinksSize - 1; i < mon->triggeringLinksSize; i--) {
        /* Get the triggered MonitoredItem. Remove the link if the MI doesn't exist. */
        UA_MonitoredItem *triggeredMon =
            UA_Subscription_getMonitoredItem(sub, mon->triggeringLinks[i]);
        if(!triggeredMon) {
            UA_MonitoredItem_removeLink(sub, mon, mon->triggeringLinks[i]);
            continue;
        }

        /* Only sampling MonitoredItems receive a trigger. Reporting
         * MonitoredItems send out Notifications anyway and disabled
         * MonitoredItems don't create samples to send. */
        if(triggeredMon->monitoringMode != UA_MONITORINGMODE_SAMPLING)
            continue;

        /* Get the latest sampled Notification from the triggered MonitoredItem.
         * Enqueue for publication. */
        UA_Notification *n2 = TAILQ_LAST(&triggeredMon->queue, NotificationQueue);
        if(n2)
            UA_Notification_enqueueSub(n2);

        /* The next Notification within the publishing interval is going to be
         * published as well. (Falsely) assume that the publishing cycle has
         * started right now, so that we don't have to loop over MonitoredItems
         * to deactivate the triggering after the publishing cycle. */
        triggeredMon->triggeredUntil = nowMonotonic +
            (UA_DateTime)(sub->publishingInterval * (UA_Double)UA_DATETIME_MSEC);

        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "MonitoredItem %u triggers MonitoredItem %u",
                                  mon->monitoredItemId, triggeredMon->monitoredItemId);
    }

    /* If we just enqueued a notification into the local adminSubscription, then
     * register a delayed callback for "local publishing". */
    if(sub == server->adminSubscription && !sub->delayedCallbackRegistered) {
        sub->delayedCallbackRegistered = true;
        sub->delayedMoreNotifications.callback =
            (UA_Callback)UA_Subscription_localPublish;
        sub->delayedMoreNotifications.application = server;
        sub->delayedMoreNotifications.context = sub;

        el = server->config.eventLoop;
        el->addDelayedCallback(el, &sub->delayedMoreNotifications);
    }
}

/* Remove from the MonitoredItem queue. This only happens if the Notification is
 * deleted right after. */
static void
UA_Notification_dequeueMon(UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);

    /* Remove from the MonitoredItem queue */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(n->isOverflowEvent)
        --mon->eventOverflows;
#endif

    TAILQ_REMOVE(&mon->queue, n, monEntry);
    --mon->queueSize;

    /* Test for consistency */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);
}

void
UA_Notification_dequeueSub(UA_Notification *n) {
    if(TAILQ_NEXT(n, subEntry) == UA_SUBSCRIPTION_QUEUE_SENTINEL)
        return;

    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);
    UA_Subscription *sub = mon->subscription;
    UA_assert(sub);

    switch(mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        --sub->eventNotifications;
        break;
#endif
    default:
        --sub->dataChangeNotifications;
        break;
    }

    TAILQ_REMOVE(&sub->notificationQueue, n, subEntry);
    --sub->notificationQueueSize;

    /* Reset the sentinel */
    TAILQ_NEXT(n, subEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL;
}

/****************/
/* Subscription */
/****************/

UA_Subscription *
UA_Subscription_new(void) {
    /* Allocate the memory */
    UA_Subscription *newSub = (UA_Subscription*)UA_calloc(1, sizeof(UA_Subscription));
    if(!newSub)
        return NULL;

    /* The first publish response is sent immediately */
    newSub->state = UA_SUBSCRIPTIONSTATE_STOPPED;

    /* Even if the first publish response is a keepalive the sequence number is 1.
     * This can happen by a subscription without a monitored item (see CTT test scripts). */
    newSub->nextSequenceNumber = 1;

    TAILQ_INIT(&newSub->retransmissionQueue);
    TAILQ_INIT(&newSub->notificationQueue);
    return newSub;
}

static void
delayedFreeSubscription(void *app, void *context) {
    UA_free(context);
}

void
UA_Subscription_delete(UA_Server *server, UA_Subscription *sub) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_EventLoop *el = server->config.eventLoop;

    /* Delete monitored Items */
    UA_assert(server->monitoredItemsSize >= sub->monitoredItemsSize);
    UA_MonitoredItem *mon, *tmp_mon;
    LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, tmp_mon) {
        UA_MonitoredItem_delete(server, mon);
    }
    UA_assert(sub->monitoredItemsSize == 0);

    /* Unregister the publish callback and possible delayed callback */
    Subscription_setState(server, sub, UA_SUBSCRIPTIONSTATE_REMOVING);

    /* Remove delayed callbacks for processing remaining notifications */
    if(sub->delayedCallbackRegistered) {
        el->removeDelayedCallback(el, &sub->delayedMoreNotifications);
        sub->delayedCallbackRegistered = false;
    }

    /* Remove the diagnostics object for the subscription */
#ifdef UA_ENABLE_DIAGNOSTICS
    if(!UA_NodeId_isNull(&sub->ns0Id))
        deleteNode(server, sub->ns0Id, true);
    UA_NodeId_clear(&sub->ns0Id);
#endif

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub, "Subscription deleted");

    /* Detach from the session if necessary */
    if(sub->session)
        UA_Session_detachSubscription(server, sub->session, sub, true);

    /* Remove from the server if not previously registered */
    if(sub->serverListEntry.le_prev) {
        LIST_REMOVE(sub, serverListEntry);
        UA_assert(server->subscriptionsSize > 0);
        server->subscriptionsSize--;
        /* Only decrement the counter if this subscription was not transferred.
         * Transferred subscriptions are replaced by a new subscription object
         * that continues to exist, so the diagnostic counter should not change. */
        if(!sub->wasTransferred) {
            server->serverDiagnosticsSummary.currentSubscriptionCount--;
        }
    }

    /* Delete Retransmission Queue */
    UA_NotificationMessageEntry *nme, *nme_tmp;
    TAILQ_FOREACH_SAFE(nme, &sub->retransmissionQueue, listEntry, nme_tmp) {
        TAILQ_REMOVE(&sub->retransmissionQueue, nme, listEntry);
        UA_NotificationMessage_clear(&nme->message);
        UA_free(nme);
        if(sub->session)
            --sub->session->totalRetransmissionQueueSize;
        --sub->retransmissionQueueSize;
    }
    UA_assert(sub->retransmissionQueueSize == 0);

    /* Pointers to the subscription may still exist upwards in the call stack.
     * Add a delayed callback to remove the Subscription when the current jobs
     * have completed. */
    sub->delayedFreePointers.callback = delayedFreeSubscription;
    sub->delayedFreePointers.application = NULL;
    sub->delayedFreePointers.context = sub;
    el->addDelayedCallback(el, &sub->delayedFreePointers);
}

void
Subscription_resetLifetime(UA_Subscription *sub) {
    sub->currentLifetimeCount = 0;
}

UA_MonitoredItem *
UA_Subscription_getMonitoredItem(UA_Subscription *sub, UA_UInt32 monitoredItemId) {
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        if(mon->monitoredItemId == monitoredItemId)
            break;
    }
    return mon;
}

static void
removeOldestRetransmissionMessageFromSub(UA_Subscription *sub) {
    UA_NotificationMessageEntry *oldestEntry =
        TAILQ_LAST(&sub->retransmissionQueue, NotificationMessageQueue);
    TAILQ_REMOVE(&sub->retransmissionQueue, oldestEntry, listEntry);
    UA_NotificationMessage_clear(&oldestEntry->message);
    UA_free(oldestEntry);
    --sub->retransmissionQueueSize;
    if(sub->session)
        --sub->session->totalRetransmissionQueueSize;

#ifdef UA_ENABLE_DIAGNOSTICS
    sub->discardedMessageCount++;
#endif
}

static void
removeOldestRetransmissionMessageFromSession(UA_Session *session) {
    UA_NotificationMessageEntry *oldestEntry = NULL;
    UA_Subscription *oldestSub = NULL;
    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        UA_NotificationMessageEntry *first =
            TAILQ_LAST(&sub->retransmissionQueue, NotificationMessageQueue);
        if(!first)
            continue;
        if(!oldestEntry || oldestEntry->message.publishTime > first->message.publishTime) {
            oldestEntry = first;
            oldestSub = sub;
        }
    }
    UA_assert(oldestEntry);
    UA_assert(oldestSub);

    removeOldestRetransmissionMessageFromSub(oldestSub);
}

static void
UA_Subscription_addRetransmissionMessage(UA_Server *server, UA_Subscription *sub,
                                         UA_NotificationMessageEntry *entry) {
    /* Release the oldest entry if there is not enough space */
    UA_Session *session = sub->session;
    if(sub->retransmissionQueueSize >= UA_MAX_RETRANSMISSIONQUEUESIZE) {
        UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                    "Subscription retransmission queue overflow");
        removeOldestRetransmissionMessageFromSub(sub);
    } else if(session && server->config.maxRetransmissionQueueSize > 0 &&
              session->totalRetransmissionQueueSize >=
              server->config.maxRetransmissionQueueSize) {
        UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                    "Session-wide retransmission queue overflow");
        removeOldestRetransmissionMessageFromSession(sub->session);
    }

    /* Add entry */
    TAILQ_INSERT_TAIL(&sub->retransmissionQueue, entry, listEntry);
    ++sub->retransmissionQueueSize;
    if(session)
        ++session->totalRetransmissionQueueSize;
}

UA_StatusCode
UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub, UA_UInt32 sequenceNumber) {
    /* Find the retransmission message */
    UA_NotificationMessageEntry *entry;
    TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) {
        if(entry->message.sequenceNumber == sequenceNumber)
            break;
    }
    if(!entry)
        return UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN;

    /* Remove the retransmission message */
    TAILQ_REMOVE(&sub->retransmissionQueue, entry, listEntry);
    --sub->retransmissionQueueSize;
    UA_NotificationMessage_clear(&entry->message);
    UA_free(entry);

    if(sub->session)
        --sub->session->totalRetransmissionQueueSize;

    return UA_STATUSCODE_GOOD;
}

/* The output counters are only set when the preparation is successful */
static UA_StatusCode
prepareNotificationMessage(UA_Server *server, UA_Subscription *sub,
                           UA_NotificationMessage *message,
                           size_t maxNotifications) {
    UA_assert(maxNotifications > 0);

    /* Allocate an ExtensionObject for Event- and DataChange-Notifications. Also
     * there can be StatusChange-Notifications. The standard says in Part 4,
     * 7.2.1:
     *
     * If a Subscription contains MonitoredItems for events and data, this array
     * should have not more than 2 elements. */
    message->notificationData = (UA_ExtensionObject*)
        UA_Array_new(2, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
    if(!message->notificationData)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    message->notificationDataSize = 2;

    /* Pre-allocate DataChangeNotifications */
    size_t notificationDataIdx = 0;
    size_t dcnPos = 0; /* How many DataChangeNotifications? */
    UA_DataChangeNotification *dcn = NULL;
    if(sub->dataChangeNotifications > 0) {
        dcn = UA_DataChangeNotification_new();
        if(!dcn) {
            UA_NotificationMessage_clear(message);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        UA_ExtensionObject_setValue(message->notificationData, dcn,
                                    &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]);
        size_t dcnSize = sub->dataChangeNotifications;
        if(dcnSize > maxNotifications)
            dcnSize = maxNotifications;
        dcn->monitoredItems = (UA_MonitoredItemNotification*)
            UA_Array_new(dcnSize, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]);
        if(!dcn->monitoredItems) {
            UA_NotificationMessage_clear(message); /* Also frees the dcn */
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        dcn->monitoredItemsSize = dcnSize;
        notificationDataIdx++;
    }

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    size_t enlPos = 0; /* How many EventNotifications? */
    UA_EventNotificationList *enl = NULL;
    if(sub->eventNotifications > 0) {
        enl = UA_EventNotificationList_new();
        if(!enl) {
            UA_NotificationMessage_clear(message);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        UA_ExtensionObject_setValue(&message->notificationData[notificationDataIdx],
                                    enl, &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]);
        size_t enlSize = sub->eventNotifications;
        if(enlSize > maxNotifications)
            enlSize = maxNotifications;
        enl->events = (UA_EventFieldList*)
            UA_Array_new(enlSize, &UA_TYPES[UA_TYPES_EVENTFIELDLIST]);
        if(!enl->events) {
            UA_NotificationMessage_clear(message);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        enl->eventsSize = enlSize;
        notificationDataIdx++;
    }
#endif

    UA_assert(notificationDataIdx > 0);
    message->notificationDataSize = notificationDataIdx;

    /* <-- The point of no return --> */

    /* How many notifications were moved to the response overall? */
    size_t totalNotifications = 0;
    UA_Notification *n, *n_tmp;
    TAILQ_FOREACH_SAFE(n, &sub->notificationQueue, subEntry, n_tmp) {
        if(totalNotifications >= maxNotifications)
            break;

        /* Move the content to the response */
        switch(n->mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        case UA_ATTRIBUTEID_EVENTNOTIFIER:
            UA_assert(enl != NULL); /* Have at least one event notification */
            enl->events[enlPos] = n->data.event;
            UA_EventFieldList_init(&n->data.event);
            enlPos++;
            break;
#endif
        default:
            UA_assert(dcn != NULL); /* Have at least one change notification */
            dcn->monitoredItems[dcnPos] = n->data.dataChange;
            UA_DataValue_init(&n->data.dataChange.value);
            dcnPos++;
            break;
        }

        /* If there are Notifications *before this one* in the MonitoredItem-
         * local queue, remove all of them. These are earlier Notifications that
         * are non-reporting. And we don't want them to show up after the
         * current Notification has been sent out. */
        UA_Notification *prev;
        while((prev = TAILQ_PREV(n, NotificationQueue, monEntry))) {
            UA_Notification_delete(prev);

            /* Help the Clang scan-analyzer */
            UA_assert(prev != TAILQ_PREV(n, NotificationQueue, monEntry));
        }

        /* Delete the notification, remove from the queues and decrease the counters */
        UA_Notification_delete(n);

        totalNotifications++;
    }

    /* Set sizes */
    if(dcn) {
        dcn->monitoredItemsSize = dcnPos;
        if(dcnPos == 0) {
            UA_free(dcn->monitoredItems);
            dcn->monitoredItems = NULL;
        }
    }

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(enl) {
        enl->eventsSize = enlPos;
        if(enlPos == 0) {
            UA_free(enl->events);
            enl->events = NULL;
        }
    }
#endif

    return UA_STATUSCODE_GOOD;
}

/* According to OPC Unified Architecture, Part 4 5.13.1.1 i) The value 0 is
 * never used for the sequence number */
static UA_UInt32
UA_Subscription_nextSequenceNumber(UA_UInt32 sequenceNumber) {
    UA_UInt32 nextSequenceNumber = sequenceNumber + 1;
    if(nextSequenceNumber == 0)
        nextSequenceNumber = 1;
    return nextSequenceNumber;
}

static void
sendStatusChangeDelete(UA_Server *server, UA_Subscription *sub,
                       UA_PublishResponseEntry *pre) {
    /* Cannot send out the StatusChange because no response is queued. Delete
     * the Subscription without sending the StatusChange. */
    if(!pre) {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "Cannot send the StatusChange notification because "
                                  "no response is queued.");
        if(UA_StatusCode_isBad(sub->statusChange)) {
            UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                      "Removing the subscription.");
            UA_Subscription_delete(server, sub);
        }
        return;
    }

    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sending out a StatusChange notification and "
                              "removing the subscription");

    UA_EventLoop *el = server->config.eventLoop;

    /* Populate the response */
    UA_PublishResponse *response = &pre->response;

    UA_StatusChangeNotification scn;
    UA_StatusChangeNotification_init(&scn);
    scn.status = sub->statusChange;

    UA_ExtensionObject notificationData;
    UA_ExtensionObject_setValue(&notificationData, &scn,
                                &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]);

    response->notificationMessage.notificationData = &notificationData;
    response->notificationMessage.notificationDataSize = 1;
    response->subscriptionId = sub->subscriptionId;
    response->notificationMessage.publishTime = el->dateTime_now(el);
    response->notificationMessage.sequenceNumber = sub->nextSequenceNumber;

    /* Send the response */
    UA_assert(sub->session); /* Otherwise pre is NULL */
    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sending out a publish response");
    sendResponse(server, sub->session->channel, pre->requestId,
                 (UA_Response *)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);

    /* Clean up */
    response->notificationMessage.notificationData = NULL;
    response->notificationMessage.notificationDataSize = 0;
    UA_PublishResponse_clear(&pre->response);
    UA_free(pre);

    /* Delete the subscription */
    UA_Subscription_delete(server, sub);
}

/* The local adminSubscription forwards notifications to a registered callback
 * method. This is done async from a delayed callback registered in the
 * EventLoop. */
void
UA_Subscription_localPublish(UA_Server *server, UA_Subscription *sub) {
    lockServer(server);
    sub->delayedCallbackRegistered = false;

    UA_Notification *n, *n_tmp;
    TAILQ_FOREACH_SAFE(n, &sub->notificationQueue, subEntry, n_tmp) {
        UA_MonitoredItem *mon = n->mon;
        UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*)mon;

        /* Move the content to the response */
        void *nodeContext = NULL;
        switch(mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        case UA_ATTRIBUTEID_EVENTNOTIFIER:
            /* Set the fields in the key-value map */
            UA_assert(n->data.event.eventFieldsSize == localMon->eventFields.mapSize);
            for(size_t i = 0; i < localMon->eventFields.mapSize; i++) {
                localMon->eventFields.map[i].value = n->data.event.eventFields[i];
            }

            /* Call the callback */
            localMon->callback.
                eventCallback(server, mon->monitoredItemId, localMon->context,
                              localMon->eventFields);
            break;
#endif
        default:
            getNodeContext(server, mon->itemToMonitor.nodeId, &nodeContext);
            localMon->callback.
                dataChangeCallback(server, mon->monitoredItemId, localMon->context,
                                   &mon->itemToMonitor.nodeId, nodeContext,
                                   mon->itemToMonitor.attributeId,
                                   &n->data.dataChange.value);
            break;
        }

        /* If there are Notifications *before this one* in the MonitoredItem-
         * local queue, remove all of them. These are earlier Notifications that
         * are non-reporting. And we don't want them to show up after the
         * current Notification has been sent out. */
        UA_Notification *prev;
        while((prev = TAILQ_PREV(n, NotificationQueue, monEntry))) {
            UA_Notification_delete(prev);

            /* Help the Clang scan-analyzer */
            UA_assert(prev != TAILQ_PREV(n, NotificationQueue, monEntry));
        }

        /* Delete the notification, remove from the queues and decrease the counters */
        UA_Notification_delete(n);
    }

    unlockServer(server);
}

static void
delayedPublishNotifications(UA_Server *server, UA_Subscription *sub) {
    lockServer(server);
    sub->delayedCallbackRegistered = false;
    UA_Subscription_publish(server, sub);
    unlockServer(server);
}

/* Try to publish now. Enqueue a "next publish" as a delayed callback if not
 * done. */
void
UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) {
    UA_EventLoop *el = server->config.eventLoop;

    /* Get a response */
    UA_PublishResponseEntry *pre = NULL;
    if(sub->session) {
        UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
        do {
            /* Dequeue the oldest response */
            pre = UA_Session_dequeuePublishReq(sub->session);
            if(!pre)
                break;

            /* Check if the TimeoutHint is still valid. Otherwise return with a bad
             * statuscode and continue. */
            if(pre->maxTime < nowMonotonic) {
                UA_LOG_DEBUG_SESSION(server->config.logging, sub->session,
                                     "Publish request %u has timed out", pre->requestId);
                pre->response.responseHeader.serviceResult = UA_STATUSCODE_BADTIMEOUT;
                sendResponse(server, sub->session->channel, pre->requestId,
                             (UA_Response *)&pre->response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
                UA_PublishResponse_clear(&pre->response);
                UA_free(pre);
                pre = NULL;
            }
        } while(!pre);
    }

    /* Update the LifetimeCounter */
    if(pre) {
        Subscription_resetLifetime(sub);
    } else {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "The publish queue is empty");
        ++sub->currentLifetimeCount;
        if(sub->currentLifetimeCount > sub->lifeTimeCount) {
            UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                        "End of subscription lifetime");
            /* Set the StatusChange to delete the subscription. */
            sub->statusChange = UA_STATUSCODE_BADTIMEOUT;
        }
    }

    /* Send a StatusChange notification if possible and delete the
     * Subscription */
    if(sub->statusChange != UA_STATUSCODE_GOOD) {
        sendStatusChangeDelete(server, sub, pre);
        return;
    }

    /* Dsiabled subscriptions do not send notifications */
    UA_UInt32 notifications = (sub->state == UA_SUBSCRIPTIONSTATE_ENABLED) ?
        sub->notificationQueueSize : 0;

    /* Limit the number of notifications to the configured maximum */
    if(notifications > sub->notificationsPerPublish)
        notifications = sub->notificationsPerPublish;

    /* Return if no notifications and no keepalive */
    if(notifications == 0) {
        ++sub->currentKeepAliveCount;
        if(sub->currentKeepAliveCount < sub->maxKeepAliveCount) {
            if(pre)
                UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
            return;
        }
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub, "Sending a KeepAlive");
    }

    /* We want to send a response, but cannot. Either because there is no queued
     * response or because the Subscription is detached from a Session or because
     * the SecureChannel for the Session is closed. */
    if(!pre || !sub->session || !sub->session->channel) {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "Want to send a publish response but cannot. "
                                  "The subscription is late.");
        sub->late = true;
        if(pre)
            UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
        return;
    }

    UA_assert(pre);
    UA_assert(sub->session); /* Otherwise pre is NULL */

    /* Prepare the response */
    UA_PublishResponse *response = &pre->response;
    UA_NotificationMessage *message = &response->notificationMessage;
    UA_NotificationMessageEntry *retransmission = NULL;
#ifdef UA_ENABLE_DIAGNOSTICS
    size_t priorDataChangeNotifications = sub->dataChangeNotifications;
    size_t priorEventNotifications = sub->eventNotifications;
#endif
    if(notifications > 0) {
        if(server->config.enableRetransmissionQueue) {
            /* Allocate the retransmission entry */
            retransmission = (UA_NotificationMessageEntry*)
                UA_malloc(sizeof(UA_NotificationMessageEntry));
            if(!retransmission) {
                UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                            "Could not allocate memory for retransmission. "
                                            "The subscription is late.");
                sub->late = true;
                UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
                return;
            }
        }

        /* Prepare the response */
        UA_StatusCode retval =
            prepareNotificationMessage(server, sub, message, notifications);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                        "Could not prepare the notification message. "
                                        "The subscription is late.");
            /* If the retransmission queue is enabled a retransmission message is allocated */
            if(retransmission)
                UA_free(retransmission);
            sub->late = true;
            UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
            return;
        }
    }

    /* <-- The point of no return --> */

    /* Set up the response */
    response->subscriptionId = sub->subscriptionId;
    response->moreNotifications = (sub->notificationQueueSize > 0);
    message->publishTime = el->dateTime_now(el);

    /* Set sequence number to message. Started at 1 which is given during
     * creating a new subscription. The 1 is required for initial publish
     * response with or without an monitored item. */
    message->sequenceNumber = sub->nextSequenceNumber;

    if(notifications > 0) {
        /* If the retransmission queue is enabled a retransmission message is
         * allocated */
        if(retransmission) {
            /* Put the notification message into the retransmission queue. This
             * needs to be done here, so that the message itself is included in
             * the available sequence numbers for acknowledgement. */
            retransmission->message = response->notificationMessage;
            UA_Subscription_addRetransmissionMessage(server, sub, retransmission);
        }
        /* Only if a notification was created, the sequence number must be
         * increased. For a keepalive the sequence number can be reused. */
        sub->nextSequenceNumber =
            UA_Subscription_nextSequenceNumber(sub->nextSequenceNumber);
    }

    /* Get the available sequence numbers from the retransmission queue */
    UA_assert(sub->retransmissionQueueSize <= UA_MAX_RETRANSMISSIONQUEUESIZE);
    UA_UInt32 seqNumbers[UA_MAX_RETRANSMISSIONQUEUESIZE];
    response->availableSequenceNumbers = seqNumbers;
    response->availableSequenceNumbersSize = sub->retransmissionQueueSize;
    size_t i = 0;
    UA_NotificationMessageEntry *nme;
    TAILQ_FOREACH(nme, &sub->retransmissionQueue, listEntry) {
        response->availableSequenceNumbers[i] = nme->message.sequenceNumber;
        ++i;
    }
    UA_assert(i == sub->retransmissionQueueSize);

    /* Send the response */
    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sending out a publish response with %" PRIu32
                              " notifications", notifications);
    sendResponse(server, sub->session->channel, pre->requestId,
                 (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);

    /* Reset the Subscription state to NORMAL. But only if all notifications
     * have been sent out. Otherwise keep the Subscription in the LATE state. So
     * we immediately answer incoming Publish requests.
     *
     * (We also check that session->responseQueueSize > 0 in Service_Publish. To
     * avoid answering Publish requests out of order. As we additionally may have
     * scheduled a publish callback as a delayed callback. */
    if(sub->notificationQueueSize == 0)
        sub->late = false;

    /* Reset the KeepAlive after publishing */
    sub->currentKeepAliveCount = 0;

    /* Free the response */
    if(retransmission) {
        /* NotificationMessage was moved into retransmission queue */
        UA_NotificationMessage_init(&response->notificationMessage);
    }
    response->availableSequenceNumbers = NULL;
    response->availableSequenceNumbersSize = 0;
    UA_PublishResponse_clear(&pre->response);
    UA_free(pre);

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->publishRequestCount++;

    UA_UInt32 sentDCN = (UA_UInt32)
        (priorDataChangeNotifications - sub->dataChangeNotifications);
    UA_UInt32 sentEN = (UA_UInt32)(priorEventNotifications - sub->eventNotifications);
    sub->dataChangeNotificationsCount += sentDCN;
    sub->eventNotificationsCount += sentEN;
    sub->notificationsCount += (sentDCN + sentEN);
#endif

    /* Repeat sending notifications if there are more notifications to send. But
     * only call UA_MonitoredItem_sample in the regular publish callback. */
    UA_Boolean done = (sub->notificationQueueSize == 0);
    if(!done && !sub->delayedCallbackRegistered) {
        sub->delayedCallbackRegistered = true;

        sub->delayedMoreNotifications.callback = (UA_Callback)delayedPublishNotifications;
        sub->delayedMoreNotifications.application = server;
        sub->delayedMoreNotifications.context = sub;

        el = server->config.eventLoop;
        el->addDelayedCallback(el, &sub->delayedMoreNotifications);
    }
}

void
UA_Subscription_resendData(UA_Server *server, UA_Subscription *sub) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_assert(server);
    UA_assert(sub);

    /* Part 4, §6.7: If this Method is called, subsequent Publish responses
     * shall contain the current values of all data MonitoredItems in the
     * Subscription where the MonitoringMode is set to Reporting. If a value is
     * queued for a data MonitoredItem, the next value in the queue is sent in
     * the Publish response. If no value is queued for a data MonitoredItem, the
     * last value sent is repeated in the Publish response. */
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        /* Create only DataChange notifications */
        if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER)
            continue;

        /* Only if the mode is monitoring */
        if(mon->monitoringMode != UA_MONITORINGMODE_REPORTING)
            continue;

        /* If a value is queued for a data MonitoredItem, the next value in
         * the queue is sent in the Publish response. */
        if(mon->queueSize > 0)
            continue;

        /* Create a notification with the last sampled value */
        UA_MonitoredItem_createDataChangeNotification(server, mon, &mon->lastValue);
    }
}

void
UA_Session_ensurePublishQueueSpace(UA_Server* server, UA_Session* session) {
    if(server->config.maxPublishReqPerSession == 0)
        return;

    while(session->responseQueueSize >= server->config.maxPublishReqPerSession) {
        /* Dequeue a response */
        UA_PublishResponseEntry *pre = UA_Session_dequeuePublishReq(session);
        UA_assert(pre != NULL); /* There must be a pre as session->responseQueueSize > 0 */

        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Sending out a publish response triggered by too many publish requests");

        /* Send the response. This response has no related subscription id */
        UA_PublishResponse *response = &pre->response;
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS;
        sendResponse(server, session->channel, pre->requestId,
                     (UA_Response *)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);

        /* Free the response */
        UA_PublishResponse_clear(response);
        UA_free(pre);
    }
}

static void
sampleAndPublishCallback(UA_Server *server, UA_Subscription *sub) {
    UA_assert(sub);

    lockServer(server);

    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sample and Publish Callback");

    /* Sample the MonitoredItems with sampling interval <0 (which implies
     * sampling in the same interval as the subscription) */
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->samplingMonitoredItems, sampling.subscriptionSampling) {
        UA_MonitoredItem_sample(server, mon);
    }

    /* Publish the queued notifications */
    UA_Subscription_publish(server, sub);

    unlockServer(server);
}

UA_StatusCode
Subscription_setState(UA_Server *server, UA_Subscription *sub,
                      UA_SubscriptionState state) {
    if(state <= UA_SUBSCRIPTIONSTATE_REMOVING) {
        if(sub->publishCallbackId != 0) {
            removeCallback(server, sub->publishCallbackId);
            sub->publishCallbackId = 0;
#ifdef UA_ENABLE_DIAGNOSTICS
            sub->disableCount++;
#endif
        }
    } else if(sub->publishCallbackId == 0) {
        UA_StatusCode res =
            addRepeatedCallback(server, (UA_ServerCallback)sampleAndPublishCallback,
                                sub, sub->publishingInterval, &sub->publishCallbackId);
        if(res != UA_STATUSCODE_GOOD) {
            sub->state = UA_SUBSCRIPTIONSTATE_STOPPED;
            return res;
        }

        /* Send (at least a) keepalive after the next publish interval */
        sub->currentKeepAliveCount = sub->maxKeepAliveCount;

#ifdef UA_ENABLE_DIAGNOSTICS
        sub->enableCount++;
#endif
    }

    sub->state = state;
    return UA_STATUSCODE_GOOD;
}

/****************/
/* Notification */
/****************/

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

/* The specification states in Part 4 5.12.1.5 that an EventQueueOverflowEvent
 * "is generated when the first Event has to be discarded [...] without
 * discarding any other event". So only generate one for all deleted events. */
static UA_StatusCode
createEventOverflowNotification(UA_Server *server, UA_Subscription *sub,
                                UA_MonitoredItem *mon) {
    /* Avoid creating two adjacent overflow events */
    UA_Notification *indicator = NULL;
    if(mon->parameters.discardOldest) {
        indicator = TAILQ_FIRST(&mon->queue);
        UA_assert(indicator); /* must exist */
        if(indicator->isOverflowEvent)
            return UA_STATUSCODE_GOOD;
    } else {
        indicator = TAILQ_LAST(&mon->queue, NotificationQueue);
        UA_assert(indicator); /* must exist */
        /* Skip the last element. It is the recently added notification that
         * shall be kept. We know it is not an OverflowEvent. */
        UA_Notification *before = TAILQ_PREV(indicator, NotificationQueue, monEntry);
        if(before && before->isOverflowEvent)
            return UA_STATUSCODE_GOOD;
    }

    /* A Notification is inserted into the queue which includes only the
     * NodeId of the OverflowEventType. */

    /* Get the EventFilter */
    if(mon->parameters.filter.content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER])
        return UA_STATUSCODE_BADINTERNALERROR;
    const UA_EventFilter *ef = (const UA_EventFilter*)
        mon->parameters.filter.content.decoded.data;
    if(ef->selectClausesSize == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Initialize the notification */
    UA_Notification *n = UA_Notification_new();
    if(!n)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    n->isOverflowEvent = true;
    n->mon = mon;
    n->data.event.clientHandle = mon->parameters.clientHandle;

    /* The session is needed to evaluate the select-clause. But used only for
     * limited reads on the source node. So we can use the admin-session here if
     * the subscription is detached. */
    UA_Session *session = (sub->session) ? sub->session : &server->adminSession;

    /* Set up the context for the filter evaluation */
    static UA_String sourceName = UA_STRING_STATIC("Internal/EventQueueOverflow");
    UA_KeyValuePair fields[1];
    fields[0].key = (UA_QualifiedName){1, UA_STRING_STATIC("/SourceName")};
    UA_Variant_setScalar(&fields[0].value, &sourceName, &UA_TYPES[UA_TYPES_STRING]);
    UA_KeyValueMap fieldMap = {1, fields};

    UA_FilterEvalContext ctx;
    UA_FilterEvalContext_init(&ctx);
    ctx.server = server;
    ctx.session = session;
    ctx.filter = *ef;
    ctx.ed.sourceNode = UA_NS0ID(SERVER);
    ctx.ed.eventType = UA_NS0ID(EVENTQUEUEOVERFLOWEVENTTYPE);
    ctx.ed.severity = 201; /* TODO: Can this be configured? */
    ctx.ed.message = UA_LOCALIZEDTEXT(NULL, NULL);
    ctx.ed.eventFields = &fieldMap;

    /* Evaluate the select clause to populate the notification */
    UA_StatusCode res = evaluateSelectClause(&ctx, &n->data.event);
    UA_FilterEvalContext_reset(&ctx);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(n);
        return res;
    }

    /* Insert before the removed notification. This is either first in the
     * queue (if the oldest notification was removed) or before the new event
     * that remains the last element of the queue.
     *
     * Ensure that the following is consistent with UA_Notification_enqueueMon
     * and UA_Notification_enqueueSub! */
    TAILQ_INSERT_BEFORE(indicator, n, monEntry);
    ++mon->eventOverflows;
    ++mon->queueSize;

    /* Test for consistency */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);

    if(TAILQ_NEXT(indicator, subEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
        /* Insert just before the indicator */
        TAILQ_INSERT_BEFORE(indicator, n, subEntry);
    } else {
        /* The indicator was not reporting or not added yet. */
        if(!mon->parameters.discardOldest) {
            /* Add last to the per-Subscription queue */
            TAILQ_INSERT_TAIL(&mon->subscription->notificationQueue,
                              n, subEntry);
        } else {
            /* Find the oldest reported element. Add before that. */
            while(indicator) {
                indicator = TAILQ_PREV(indicator, NotificationQueue, monEntry);
                if(!indicator) {
                    TAILQ_INSERT_TAIL(&mon->subscription->notificationQueue,
                                      n, subEntry);
                    break;
                }
                if(TAILQ_NEXT(indicator, subEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
                    TAILQ_INSERT_BEFORE(indicator, n, subEntry);
                    break;
                }
            }
        }
    }

    ++sub->notificationQueueSize;
    ++sub->eventNotifications;

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->eventQueueOverflowCount++;
#endif

    return UA_STATUSCODE_GOOD;
}

#endif

/* Set the InfoBits that a datachange notification was removed */
static void
setOverflowInfoBits(UA_MonitoredItem *mon) {
    /* Only for queues with more than one element */
    if(mon->parameters.queueSize == 1)
        return;

    UA_Notification *indicator = NULL;
    if(mon->parameters.discardOldest) {
        indicator = TAILQ_FIRST(&mon->queue);
    } else {
        indicator = TAILQ_LAST(&mon->queue, NotificationQueue);
    }
    UA_assert(indicator); /* must exist */

    indicator->data.dataChange.value.hasStatus = true;
    indicator->data.dataChange.value.status |=
        (UA_STATUSCODE_INFOTYPE_DATAVALUE | UA_STATUSCODE_INFOBITS_OVERFLOW);
}

/* Remove the InfoBits when the queueSize was reduced to 1 */
void
UA_MonitoredItem_removeOverflowInfoBits(UA_MonitoredItem *mon) {
    /* Don't consider queue size > 1 and Event MonitoredItems */
    if(mon->parameters.queueSize > 1 ||
       mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER)
        return;

    /* Get the first notification */
    UA_Notification *n = TAILQ_FIRST(&mon->queue);
    if(!n)
        return;

    /* Assertion that at most one notification is in the queue */
    UA_assert(n == TAILQ_LAST(&mon->queue, NotificationQueue));

    /* Remve the Infobits */
    n->data.dataChange.value.status &= ~(UA_StatusCode)
        (UA_STATUSCODE_INFOTYPE_DATAVALUE | UA_STATUSCODE_INFOBITS_OVERFLOW);
}

/*****************/
/* MonitoredItem */
/*****************/

void
UA_MonitoredItem_init(UA_MonitoredItem *mon) {
    memset(mon, 0, sizeof(UA_MonitoredItem));
    TAILQ_INIT(&mon->queue);
    mon->triggeredUntil = UA_INT64_MIN;
}

static UA_StatusCode
addMonitoredItemBackpointer(UA_Server *server, UA_Session *session,
                            UA_Node *node, void *data) {
    UA_MonitoredItem *mon = (UA_MonitoredItem*)data;
    UA_assert(mon != (UA_MonitoredItem*)~0);
    mon->sampling.nodeListNext = node->head.monitoredItems;
    node->head.monitoredItems = mon;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removeMonitoredItemBackPointer(UA_Server *server, UA_Session *session,
                               UA_Node *node, void *data) {
    if(!node->head.monitoredItems)
        return UA_STATUSCODE_GOOD;

    /* Edge case that it's the first element */
    UA_MonitoredItem *remove = (UA_MonitoredItem*)data;
    if(node->head.monitoredItems == remove) {
        node->head.monitoredItems = remove->sampling.nodeListNext;
        return UA_STATUSCODE_GOOD;
    }

    UA_MonitoredItem *prev = node->head.monitoredItems;
    UA_MonitoredItem *entry = prev->sampling.nodeListNext;
    for(; entry != NULL; prev = entry, entry = entry->sampling.nodeListNext) {
        if(entry == remove) {
            prev->sampling.nodeListNext = entry->sampling.nodeListNext;
            break;
        }
    }

    return UA_STATUSCODE_GOOD;
}

void
UA_MonitoredItem_register(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(mon->registered)
        return;
    mon->registered = true;

    /* Register in Subscription and Server */
    UA_Subscription *sub = mon->subscription;
    mon->monitoredItemId = ++sub->lastMonitoredItemId;
    mon->subscription = sub;
    LIST_INSERT_HEAD(&sub->monitoredItems, mon, listEntry);
    sub->monitoredItemsSize++;
    server->monitoredItemsSize++;

    /* Register the MonitoredItem in userland */
    if(server->config.monitoredItemRegisterCallback) {
        UA_Session *session = sub->session;
        void *targetContext = NULL;
        getNodeContext(server, mon->itemToMonitor.nodeId, &targetContext);
        server->config.monitoredItemRegisterCallback(server,
                                                     session ? &session->sessionId : NULL,
                                                     session ? session->context : NULL,
                                                     &mon->itemToMonitor.nodeId,
                                                     targetContext,
                                                     mon->itemToMonitor.attributeId, false);
    }
}

static void
unregisterMonitoredItem(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(!mon->registered)
        return;
    mon->registered = false;

    UA_Subscription *sub = mon->subscription;
    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                             "MonitoredItem %" PRIi32 " | Deleting the MonitoredItem",
                             mon->monitoredItemId);

    /* Deregister MonitoredItem in userland */
    if(server->config.monitoredItemRegisterCallback) {
        UA_Session *session = sub->session;
        void *targetContext = NULL;
        getNodeContext(server, mon->itemToMonitor.nodeId, &targetContext);
        server->config.monitoredItemRegisterCallback(server,
                                                     session ? &session->sessionId : NULL,
                                                     session ? session->context : NULL,
                                                     &mon->itemToMonitor.nodeId,
                                                     targetContext,
                                                     mon->itemToMonitor.attributeId, true);
    }

    /* Deregister in Subscription and server */
    sub->monitoredItemsSize--;
    LIST_REMOVE(mon, listEntry);
    server->monitoredItemsSize--;
}

UA_StatusCode
UA_MonitoredItem_setMonitoringMode(UA_Server *server, UA_MonitoredItem *mon,
                                   UA_MonitoringMode monitoringMode) {
    /* Check if the MonitoringMode is valid or not */
    if(monitoringMode > UA_MONITORINGMODE_REPORTING)
        return UA_STATUSCODE_BADMONITORINGMODEINVALID;

    /* Set the MonitoringMode, store the old mode */
    UA_MonitoringMode oldMode = mon->monitoringMode;
    mon->monitoringMode = monitoringMode;

    UA_Notification *notification;
    /* Reporting is disabled. This causes all Notifications to be dequeued and
     * deleted. Also remove the last samples so that we immediately generate a
     * Notification when re-activated. */
    if(mon->monitoringMode == UA_MONITORINGMODE_DISABLED) {
        UA_Notification *notification_tmp;
        UA_MonitoredItem_unregisterSampling(server, mon);
        TAILQ_FOREACH_SAFE(notification, &mon->queue, monEntry, notification_tmp) {
            UA_Notification_delete(notification);
        }
        UA_DataValue_clear(&mon->lastValue);
        return UA_STATUSCODE_GOOD;
    }

    /* When reporting is enabled, put all notifications that were already
     * sampled into the global queue of the subscription. When sampling is
     * enabled, remove all notifications from the global queue. !!! This needs
     * to be the same operation as in UA_Notification_enqueue !!! */
    if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING) {
        /* Make all notifications reporting. Re-enqueue to ensure they have the
         * right order if some notifications are already reported by a trigger
         * link. */
        TAILQ_FOREACH(notification, &mon->queue, monEntry) {
            UA_Notification_dequeueSub(notification);
            UA_Notification_enqueueSub(notification);
        }
    } else /* mon->monitoringMode == UA_MONITORINGMODE_SAMPLING */ {
        /* Make all notifications non-reporting */
        TAILQ_FOREACH(notification, &mon->queue, monEntry)
            UA_Notification_dequeueSub(notification);
    }

    /* Register the sampling callback with an interval. If registering the
     * sampling callback failed, set to disabled. But don't delete the current
     * notifications. */
    UA_StatusCode res = UA_MonitoredItem_registerSampling(server, mon);
    if(res != UA_STATUSCODE_GOOD) {
        mon->monitoringMode = UA_MONITORINGMODE_DISABLED;
        return res;
    }

    /* Manually create the first sample if the MonitoredItem was disabled, the
     * MonitoredItem is now sampling (or reporting) and it is not an
     * Event-MonitoredItem */
    if(oldMode == UA_MONITORINGMODE_DISABLED &&
       mon->monitoringMode > UA_MONITORINGMODE_DISABLED &&
       mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER)
        UA_MonitoredItem_sample(server, mon);

    return UA_STATUSCODE_GOOD;
}

static void
delayedFreeMonitoredItem(void *app, void *context) {
    UA_free(context);
}

void
UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Remove the sampling callback */
    UA_MonitoredItem_unregisterSampling(server, mon);

    /* Deregister in Server and Subscription */
    if(mon->registered)
        unregisterMonitoredItem(server, mon);

    /* Cancel outstanding async reads. The status code avoids the sample being
     * processed. Call _processReady to ensure that the callbacks have been
     * triggered. */
    if(mon->outstandingAsyncReads > 0)
        async_cancel(server, mon, UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST, true);
    UA_assert(mon->outstandingAsyncReads == 0);

    /* Remove the TriggeringLinks */
    if(mon->triggeringLinksSize > 0) {
        UA_free(mon->triggeringLinks);
        mon->triggeringLinks = NULL;
        mon->triggeringLinksSize = 0;
    }

    /* Remove the queued notifications attached to the subscription */
    UA_Notification *notification, *notification_tmp;
    TAILQ_FOREACH_SAFE(notification, &mon->queue, monEntry, notification_tmp) {
        UA_Notification_delete(notification);
    }

    /* Remove the settings */
    UA_ReadValueId_clear(&mon->itemToMonitor);
    UA_MonitoringParameters_clear(&mon->parameters);

    /* Remove the last samples */
    UA_DataValue_clear(&mon->lastValue);

    /* If this is a local MonitoredItem, clean up additional values */
    if(mon->subscription == server->adminSubscription) {
        UA_LocalMonitoredItem *lm = (UA_LocalMonitoredItem*)mon;
        for(size_t i = 0; i < lm->eventFields.mapSize; i++)
            UA_Variant_init(&lm->eventFields.map[i].value);
        UA_KeyValueMap_clear(&lm->eventFields);
    }

    /* Add a delayed callback to remove the MonitoredItem when the current jobs
     * have completed. This is needed to allow that a local MonitoredItem can
     * remove itself in the callback. */
    mon->delayedFreePointers.callback = delayedFreeMonitoredItem;
    mon->delayedFreePointers.application = NULL;
    mon->delayedFreePointers.context = mon;
    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, &mon->delayedFreePointers);
}

void
UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon) {
    /* There can be only one EventOverflow more than normal entries. Because
     * EventOverflows are never adjacent. */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);

    /* MonitoredItems are always attached to a Subscription */
    UA_Subscription *sub = mon->subscription;
    UA_assert(sub);

    /* Nothing to do */
    if(mon->queueSize - mon->eventOverflows <= mon->parameters.queueSize)
        return;

    /* Help clang-analyzer */
#if defined(UA_DEBUG) && defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS)
    UA_Notification *last_del = NULL;
    (void)last_del;
#endif

    /* Remove notifications until the required queue size is reached */
    UA_Boolean reporting = false;
    size_t remove = mon->queueSize - mon->eventOverflows - mon->parameters.queueSize;
    while(remove > 0) {
        /* The minimum queue size (without EventOverflows) is 1. At least two
         * notifications that are not EventOverflows are in the queue. */
        UA_assert(mon->queueSize - mon->eventOverflows >= 2);

        /* Select the next notification to delete. Skip over overflow events. */
        UA_Notification *del = NULL;
        if(mon->parameters.discardOldest) {
            /* Remove the oldest */
            del = TAILQ_FIRST(&mon->queue);
#if defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS)
            /* Skip overflow events */
            while(del->isOverflowEvent) {
                del = TAILQ_NEXT(del, monEntry);
                UA_assert(del != last_del);
            }
#endif
        } else {
            /* Remove the second newest (to keep the up-to-date notification).
             * The last entry is not an OverflowEvent -- we just added it. */
            del = TAILQ_LAST(&mon->queue, NotificationQueue);
            del = TAILQ_PREV(del, NotificationQueue, monEntry);
#if defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS)
            /* skip overflow events */
            while(del->isOverflowEvent) {
                del = TAILQ_PREV(del, NotificationQueue, monEntry);
                UA_assert(del != last_del);
            }
#endif
        }

        UA_assert(del); /* There must be one entry that can be deleted */

        /* Only create OverflowEvents (and set InfoBits) if the notification
         * that is removed is reported */
        if(TAILQ_NEXT(del, subEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL)
            reporting = true;

        /* Move the entry after del in the per-MonitoredItem queue right after
         * del in the per-Subscription queue. So we don't starve MonitoredItems
         * with a high sampling interval in the Subscription queue by always
         * removing their first appearance in the per-Subscription queue.
         *
         * With MonitoringMode == SAMPLING, the Notifications are not (all) in
         * the per-Subscription queue. Don't reinsert in that case.
         *
         * For the reinsertion to work, first insert into the per-Subscription
         * queue. */
        if(TAILQ_NEXT(del, subEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
            UA_Notification *after_del = TAILQ_NEXT(del, monEntry);
            UA_assert(after_del); /* There must be one remaining element after del */
            if(TAILQ_NEXT(after_del, subEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
                TAILQ_REMOVE(&sub->notificationQueue, after_del, subEntry);
                TAILQ_INSERT_AFTER(&sub->notificationQueue, del, after_del, subEntry);
            }
        }

        remove--;

        /* Delete the notification and remove it from the queues */
        UA_Notification_delete(del);

        /* Update the subscription diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
        sub->monitoringQueueOverflowCount++;
#endif

        /* Help scan-analyzer */
#if defined(UA_DEBUG) && defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS)
        last_del = del;
#endif
        UA_assert(del != TAILQ_FIRST(&mon->queue));
        UA_assert(del != TAILQ_LAST(&mon->queue, NotificationQueue));
        UA_assert(del != TAILQ_PREV(TAILQ_LAST(&mon->queue, NotificationQueue),
                                    NotificationQueue, monEntry));
    }

    /* Leave an entry to indicate that notifications were removed */
    if(reporting) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER)
            createEventOverflowNotification(server, sub, mon);
        else
#endif
            setOverflowInfoBits(mon);
    }
}

static void
UA_MonitoredItem_lockAndSample(UA_Server *server, UA_MonitoredItem *mon) {
    lockServer(server);
    UA_MonitoredItem_sample(server, mon);
    unlockServer(server);
}

UA_StatusCode
UA_MonitoredItem_registerSampling(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Sampling is already registered */
    if(mon->samplingType != UA_MONITOREDITEMSAMPLINGTYPE_NONE)
        return UA_STATUSCODE_GOOD;

    /* The subscription is attached to a session at this point */
    UA_Subscription *sub = mon->subscription;
    if(!sub->session)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* For SamplingInterval == 0 and Value attribute, check if the node is a
     * DataSource. DataSource nodes (e.g. internal diagnostic nodes) compute
     * their value on-the-fly via a read callback. The backpointer-based
     * sampling only triggers on OPC UA write, which never happens for
     * DataSources. Fall through to normal sampling instead. */
    UA_Boolean extValueSource = false;
    if(mon->parameters.samplingInterval == 0.0 &&
       mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_VALUE) {
        const UA_Node *node = UA_NODESTORE_GET(server, &mon->itemToMonitor.nodeId);
        if(node) {
            if(node->head.nodeClass == UA_NODECLASS_VARIABLE)
                extValueSource = VariableNode_externalDataSource(&node->variableNode);
            UA_NODESTORE_RELEASE(server, node);
        }
    }

    /* Add backpointer to the node for "event-based sampling" during write */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER ||
       (mon->parameters.samplingInterval == 0.0 && !extValueSource)) {
        /* Add to the linked list in the node */
        res = editNode(server, sub->session, &mon->itemToMonitor.nodeId, 0,
                       UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                       addMonitoredItemBackpointer, mon);
        if(res == UA_STATUSCODE_GOOD)
            mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_EVENT;
        return res;
    }

    /* Add backpointer to the subscription for sampling before every publish */
    if(mon->parameters.samplingInterval == sub->publishingInterval) {
        /* Add to the subscription for sampling before every publish */
        LIST_INSERT_HEAD(&sub->samplingMonitoredItems, mon,
                         sampling.subscriptionSampling);
        mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_PUBLISH;
        return res;
    }

    /* Standard sampling with a repeated callback */
    res = addRepeatedCallback(server,
                              (UA_ServerCallback)UA_MonitoredItem_lockAndSample,
                              mon, mon->parameters.samplingInterval,
                              &mon->sampling.callbackId);
    if(res == UA_STATUSCODE_GOOD)
        mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_CYCLIC;
    return res;
}

void
UA_MonitoredItem_unregisterSampling(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    switch(mon->samplingType) {
    case UA_MONITOREDITEMSAMPLINGTYPE_CYCLIC:
        /* Remove repeated callback */
        removeCallback(server, mon->sampling.callbackId);
        break;

    case UA_MONITOREDITEMSAMPLINGTYPE_EVENT: {
        /* Removing is always done with the AdminSession. So it also works when
         * the Subscription has been detached from its Session. */
        editNode(server, &server->adminSession, &mon->itemToMonitor.nodeId, 0,
                 UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                 removeMonitoredItemBackPointer, mon);
        break;
    }

    case UA_MONITOREDITEMSAMPLINGTYPE_PUBLISH:
        /* Added to the subscription */
        LIST_REMOVE(mon, sampling.subscriptionSampling);
        break;

    case UA_MONITOREDITEMSAMPLINGTYPE_NONE:
    default:
        /* Sampling is not registered */
        break;
    }

    mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_NONE;
}

UA_StatusCode
UA_MonitoredItem_removeLink(UA_Subscription *sub, UA_MonitoredItem *mon, UA_UInt32 linkId) {
    /* Find the index */
    size_t i = 0;
    for(; i < mon->triggeringLinksSize; i++) {
        if(mon->triggeringLinks[i] == linkId)
            break;
    }

    /* Not existing / already removed */
    if(i == mon->triggeringLinksSize)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;

    /* Remove the link */
    mon->triggeringLinksSize--;
    if(mon->triggeringLinksSize == 0) {
        UA_free(mon->triggeringLinks);
        mon->triggeringLinks = NULL;
    } else {
        mon->triggeringLinks[i] = mon->triggeringLinks[mon->triggeringLinksSize];
        UA_UInt32 *tmpLinks = (UA_UInt32*)
            UA_realloc(mon->triggeringLinks, mon->triggeringLinksSize * sizeof(UA_UInt32));
        if(tmpLinks)
            mon->triggeringLinks = tmpLinks;
    }

    /* Does the target MonitoredItem exist? This is stupid, but the CTT wants us
     * to to this. We don't auto-remove links together with the target
     * MonitoredItem. Links to removed MonitoredItems are removed when the link
     * triggers and the target no longer exists. */
    UA_MonitoredItem *mon2 = UA_Subscription_getMonitoredItem(sub, linkId);
    if(!mon2)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_MonitoredItem_addLink(UA_Subscription *sub, UA_MonitoredItem *mon, UA_UInt32 linkId) {
    /* Does the target MonitoredItem exist? */
    UA_MonitoredItem *mon2 = UA_Subscription_getMonitoredItem(sub, linkId);
    if(!mon2)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;

    /* Does the link already exist? */
    for(size_t i = 0 ; i < mon->triggeringLinksSize; i++) {
        if(mon->triggeringLinks[i] == linkId)
            return UA_STATUSCODE_GOOD;
    }

    /* Allocate the memory */
    UA_UInt32 *tmpLinkIds = (UA_UInt32*)
        UA_realloc(mon->triggeringLinks, (mon->triggeringLinksSize + 1) * sizeof(UA_UInt32));
    if(!tmpLinkIds)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    mon->triggeringLinks = tmpLinkIds;

    /* Add the link */
    mon->triggeringLinks[mon->triggeringLinksSize] = linkId;
    mon->triggeringLinksSize++;
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_subscription_datachange.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

/* Detect value changes outside the deadband */
#define UA_DETECT_DEADBAND(TYPE) do {                           \
    TYPE v1 = *(const TYPE*)data1;                              \
    TYPE v2 = *(const TYPE*)data2;                              \
    TYPE diff = (v1 > v2) ? (TYPE)(v1 - v2) : (TYPE)(v2 - v1);  \
    return ((UA_Double)diff > deadband);                        \
} while(false)

static UA_Boolean
detectScalarDeadBand(const void *data1, const void *data2,
                     const UA_DataType *type, const UA_Double deadband) {
    if(type->typeKind == UA_DATATYPEKIND_SBYTE) {
        UA_DETECT_DEADBAND(UA_SByte);
    } else if(type->typeKind == UA_DATATYPEKIND_BYTE) {
        UA_DETECT_DEADBAND(UA_Byte);
    } else if(type->typeKind == UA_DATATYPEKIND_INT16) {
        UA_DETECT_DEADBAND(UA_Int16);
    } else if(type->typeKind == UA_DATATYPEKIND_UINT16) {
        UA_DETECT_DEADBAND(UA_UInt16);
    } else if(type->typeKind == UA_DATATYPEKIND_INT32) {
        UA_DETECT_DEADBAND(UA_Int32);
    } else if(type->typeKind == UA_DATATYPEKIND_UINT32) {
        UA_DETECT_DEADBAND(UA_UInt32);
    } else if(type->typeKind == UA_DATATYPEKIND_INT64) {
        UA_DETECT_DEADBAND(UA_Int64);
    } else if(type->typeKind == UA_DATATYPEKIND_UINT64) {
        UA_DETECT_DEADBAND(UA_UInt64);
    } else if(type->typeKind == UA_DATATYPEKIND_FLOAT) {
        UA_DETECT_DEADBAND(UA_Float);
    } else if(type->typeKind == UA_DATATYPEKIND_DOUBLE) {
        UA_DETECT_DEADBAND(UA_Double);
    } else {
        return false; /* Not a known numerical type */
    }
}

static UA_Boolean
detectVariantDeadband(const UA_Variant *value, const UA_Variant *oldValue,
                      const UA_Double deadbandValue) {
    /* Be careful to avoid a NULL access. We could have the value a scalar and
     * oldValue an empty array. Both define a type and arrayLength == 0. */
    if(value->arrayLength != oldValue->arrayLength)
        return true;
    if(value->type != oldValue->type)
        return true;
    if(UA_Variant_isScalar(value) != UA_Variant_isScalar(oldValue))
        return true;

    /* Treat scalars as an array of length 1 and iterate */
    size_t length = 1;
    if(!UA_Variant_isScalar(value))
        length = value->arrayLength;

    uintptr_t data = (uintptr_t)value->data;
    uintptr_t oldData = (uintptr_t)oldValue->data;
    UA_UInt32 memSize = value->type->memSize;
    for(size_t i = 0; i < length; ++i) {
        if(detectScalarDeadBand((const void*)data, (const void*)oldData,
                                value->type, deadbandValue))
            return true;
        data += memSize;
        oldData += memSize;
    }
    return false;
}

static UA_Boolean
detectValueChange(UA_Server *server, UA_MonitoredItem *mon, const UA_DataValue *dv) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Status changes are always reported */
    if(dv->hasStatus != mon->lastValue.hasStatus ||
       dv->status != mon->lastValue.status) {
        return true;
    }

    /* Default trigger is Status + Value */
    UA_DataChangeTrigger trigger = UA_DATACHANGETRIGGER_STATUSVALUE;

    /* Use the configured trigger */
    const UA_DataChangeFilter *dcf = NULL;
    const UA_ExtensionObject *filter = &mon->parameters.filter;
    if(filter->content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) {
        dcf = (UA_DataChangeFilter*)filter->content.decoded.data;
        trigger = dcf->trigger;
    }

    /* The status was already tested above */
    if(trigger == UA_DATACHANGETRIGGER_STATUS)
        return false;

    UA_assert(trigger == UA_DATACHANGETRIGGER_STATUSVALUE ||
              trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP);

    /* Can we compare values? */
    if(dv->hasValue != mon->lastValue.hasValue)
       return true;

    /* Test absolute deadband */
    if(dcf && dcf->deadbandType == UA_DEADBANDTYPE_ABSOLUTE &&
       dv->value.type != NULL && UA_DataType_isNumeric(dv->value.type))
        return detectVariantDeadband(&dv->value, &mon->lastValue.value,
                                     dcf->deadbandValue);

    /* Compare the source timestamp if the trigger requires that */
    if(trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP) {
        if(dv->hasSourceTimestamp != mon->lastValue.hasSourceTimestamp)
            return true;
        if(dv->hasSourceTimestamp &&
           dv->sourceTimestamp != mon->lastValue.sourceTimestamp)
            return true;
    }

    /* Has the value changed? */
    return !UA_equal(&dv->value, &mon->lastValue.value,
                     &UA_TYPES[UA_TYPES_VARIANT]);
}

UA_StatusCode
UA_MonitoredItem_createDataChangeNotification(UA_Server *server, UA_MonitoredItem *mon,
                                              const UA_DataValue *dv) {
    /* Copy the value */
    UA_DataValue valueCopy;
    UA_StatusCode retval = UA_DataValue_copy(dv, &valueCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Allocate a new notification */
    UA_Notification *n = UA_Notification_new();
    if(!n) {
        UA_DataValue_clear(&valueCopy);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Prepare and enqueue the notification */
    n->mon = mon;
    n->data.dataChange.value = valueCopy;
    n->data.dataChange.clientHandle = mon->parameters.clientHandle;
    UA_Notification_enqueueAndTrigger(server, n);
    return UA_STATUSCODE_GOOD;
}

void
UA_MonitoredItem_processSampledValue(UA_Server *server, UA_MonitoredItem *mon,
                                     UA_DataValue *value) {
    UA_assert(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER);
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Has the value changed (with the filters applied)? */
    UA_Boolean changed = detectValueChange(server, mon, value);
    if(!changed) {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, mon->subscription,
                                  "MonitoredItem %" PRIi32 " | "
                                  "The value has not changed", mon->monitoredItemId);
        UA_DataValue_clear(value);
        return;
    }

    /* Prepare a notification and enqueue it */
    UA_StatusCode res =
        UA_MonitoredItem_createDataChangeNotification(server, mon, value);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, mon->subscription,
                                    "MonitoredItem %" PRIi32 " | "
                                    "Processing the sample returned the statuscode %s",
                                    mon->monitoredItemId, UA_StatusCode_name(res));
        UA_DataValue_clear(value);
        return;
    }

    /* Move/store the value for filter comparison and TransferSubscription */
    UA_DataValue_clear(&mon->lastValue);
    mon->lastValue = *value;

    /* Call the local callback if the MonitoredItem is not attached to a
     * subscription. Do this at the very end. Because the callback might delete
     * the subscription. */
    if(!mon->subscription) {
        UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*) mon;
        void *nodeContext = NULL;
        getNodeContext(server, mon->itemToMonitor.nodeId, &nodeContext);
        localMon->callback.dataChangeCallback(server,
                                              mon->monitoredItemId, localMon->context,
                                              &mon->itemToMonitor.nodeId, nodeContext,
                                              mon->itemToMonitor.attributeId, value);
    }
}

/* We know the result is a deep-copy. So we can abuse the const result-pointer
 * and take ownership of the value. */
static void
processMonitoredItemAsyncRead(UA_Server *server, UA_MonitoredItem *mon,
                              const UA_DataValue *result) {
    mon->outstandingAsyncReads--;
    UA_DataValue *mut_result = (UA_DataValue*)(uintptr_t)result;
    if(mut_result->status == UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST)
        return; /* Controlled shut-down */
    UA_MonitoredItem_processSampledValue(server, mon, mut_result);
    UA_DataValue_init(mut_result);
}

void
UA_MonitoredItem_sample(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_assert(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER);

    UA_Subscription *sub = mon->subscription;
    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub, "MonitoredItem %" PRIi32
                              " | Sample callback called", mon->monitoredItemId);

    /* Sample the current value.
     * sub->session can be NULL when the subscription is detached. Then
     * readWithSession returns the error-code BADUSERACCESSDENIED. */
    UA_Session *session = (sub) ? sub->session : &server->adminSession;

    /* Read the value possibly asynchronous */
    UA_StatusCode res = UA_STATUSCODE_BADTOOMANYOPERATIONS;
    if(UA_LIKELY(mon->outstandingAsyncReads < UA_MONITOREDITEM_ASYNC_MAX)) {
        res = read_async(server, session, &mon->itemToMonitor, mon->timestampsToReturn,
                         (UA_ServerAsyncReadResultCallback)processMonitoredItemAsyncRead, mon, 0);
    }
    if(res == UA_STATUSCODE_GOOD) {
        mon->outstandingAsyncReads++;
    } else {
        /* Reading failed, process with the StatusCode */
        UA_DataValue dv;
        UA_DataValue_init(&dv);
        dv.hasStatus = true;
        dv.status = res;
        UA_MonitoredItem_processSampledValue(server, mon, &dv);
    }
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_subscription_event.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2022, 2025 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

static UA_StatusCode
readSAOfromEventInstance(UA_FilterEvalContext *ctx,
                         const UA_SimpleAttributeOperand *sao,
                         UA_Variant *value) {
    /* EventInstance in the information model defined? */
    const UA_NodeId *ei = ctx->ed.eventInstance;
    if(!ei)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Prepare the ReadValueId */
    UA_ReadValueId rvi;
    UA_ReadValueId_init(&rvi);
    rvi.indexRange = sao->indexRange;
    rvi.attributeId = sao->attributeId;

    /* Read the value */
    UA_DataValue v;
    if(sao->browsePathSize == 0) {
        /* If this list (browsePath) is empty, the Node is the instance of the
         * TypeDefinition. (Part 4, 7.4.4.5) */
        rvi.nodeId = *ei;

        /* A Condition is an indirection. Look up the target node. */
        /* TODO: check for Branches! One Condition could have multiple Branches */
        UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
        if(UA_NodeId_equal(&sao->typeDefinitionId, &conditionTypeId)) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
            UA_StatusCode res = UA_getConditionId(ctx->server, ctx->ed.eventInstance, &rvi.nodeId);
            UA_CHECK_STATUS(res, return res);
#else
            return UA_STATUSCODE_BADNOTSUPPORTED;
#endif
        }

        v = readWithSession(ctx->server, ctx->session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
    } else {
        /* Resolve the browse path, starting from the event-source (and not the
         * typeDefinitionId). */
        UA_BrowsePathResult bpr =
            browseSimplifiedBrowsePath(ctx->server, *ei, sao->browsePathSize, sao->browsePath);
        if(bpr.targetsSize == 0 && bpr.statusCode == UA_STATUSCODE_GOOD)
            bpr.statusCode = UA_STATUSCODE_BADNOTFOUND;
        if(bpr.statusCode != UA_STATUSCODE_GOOD) {
            UA_StatusCode res = bpr.statusCode;
            UA_BrowsePathResult_clear(&bpr);
            return res;
        }

        /* Use the first match */
        rvi.nodeId = bpr.targets[0].targetId.nodeId;
        v = readWithSession(ctx->server, ctx->session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
        UA_BrowsePathResult_clear(&bpr);
    }

    /* Validate the result */
    if(v.status != UA_STATUSCODE_GOOD) {
        UA_Variant_clear(&v.value);
        return v.status;
    }
    if(!v.hasValue)
        return UA_STATUSCODE_BADNODATAAVAILABLE;

    /* Move the result to the output */
    *value = v.value;
    return UA_STATUSCODE_GOOD;
}

/***************/
/* Filter Eval */
/***************/

/* Names of the mandatory event properties (in the BaseEventType) */
#define MANDATORY_EVENT_PROPERTIES_COUNT 8
static UA_String mandatoryEventProperties[MANDATORY_EVENT_PROPERTIES_COUNT] = {
    UA_STRING_STATIC("/EventId"),
    UA_STRING_STATIC("/EventType"),
    UA_STRING_STATIC("/SourceNode"),
    UA_STRING_STATIC("/SourceName"),
    UA_STRING_STATIC("/Time"),
    UA_STRING_STATIC("/ReceiveTime"),
    UA_STRING_STATIC("/Message"),
    UA_STRING_STATIC("/Severity")
};

void
UA_FilterEvalContext_init(UA_FilterEvalContext *ctx) {
    memset(ctx, 0, sizeof(UA_FilterEvalContext));
}

void
UA_FilterEvalContext_reset(UA_FilterEvalContext *ctx) {
    UA_KeyValueMap_clear(&ctx->fieldCache);

    /* The data of the EventId is either in the eventIdBuf or in the fieldCache
     * or in the ed. So no memory to free here. Keep the EventId if it points to
     * the random-id bytes for the next evaluation. */
    if(ctx->eventId.data != ctx->eventIdBuf)
        UA_ByteString_init(&ctx->eventId);
}

UA_StatusCode
cacheEventId(UA_FilterEvalContext *ctx) {
    /* Already cached */
    if(ctx->eventId.length > 0)
        return UA_STATUSCODE_GOOD;

    /* Resolve from the Key-Value Map - This does not make a deep copy */
    const UA_EventDescription *ed = &ctx->ed;
    if(ed && ed->eventFields) {
        const UA_Variant *found =
            UA_KeyValueMap_get(ed->eventFields, UA_QUALIFIEDNAME(0, "/EventId"));
        if(found) {
            if(!UA_Variant_hasScalarType(found, &UA_TYPES[UA_TYPES_BYTESTRING]))
                return UA_STATUSCODE_BADTYPEMISMATCH;
            ctx->eventId = *(UA_ByteString*)found->data; /* shallow copy */
            return UA_STATUSCODE_GOOD;
        }
    }

    /* Resolve from the EventInstance. But only if a useful identifier
     * (ByteString, length > 0) has been set in the information model. */
    static UA_QualifiedName eventIdName = {0, UA_STRING_STATIC("EventId")};
    UA_SimpleAttributeOperand sao;
    UA_SimpleAttributeOperand_init(&sao);
    sao.attributeId = UA_ATTRIBUTEID_VALUE;
    sao.browsePath = &eventIdName;
    sao.browsePathSize = 1;

    UA_Variant val;
    UA_Variant_init(&val);
    UA_StatusCode res = readSAOfromEventInstance(ctx, &sao, &val);
    if(res == UA_STATUSCODE_GOOD) {
        UA_Boolean isIdString = UA_Variant_hasScalarType(&val, &UA_TYPES[UA_TYPES_BYTESTRING]);
        UA_assert(!isIdString || val.data != NULL); /* pacify a clang-analyzer warning */
        if(isIdString && ((UA_ByteString*)val.data)->length > 0) {
            res = UA_KeyValueMap_set(&ctx->fieldCache,
                                     UA_QUALIFIEDNAME(0, "/EventId"), &val);
            UA_Variant_clear(&val);
            if(res != UA_STATUSCODE_GOOD)
                return res;
            const UA_Variant *cached =
                UA_KeyValueMap_get(&ctx->fieldCache,
                                   UA_QUALIFIEDNAME(0, "/EventId"));
            ctx->eventId = *(UA_ByteString*)cached->data; /* shallow copy */
            return UA_STATUSCODE_GOOD;
        }

        /* Continue to create a random ByteString */
        UA_Variant_clear(&val);
    }

    /* If nothing is explicitly defined, create a random 16-byte ByteString */
    UA_UInt32 *ids = (UA_UInt32*)ctx->eventIdBuf;
    ids[0] = UA_UInt32_random();
    ids[1] = UA_UInt32_random();
    ids[2] = UA_UInt32_random();
    ids[3] = UA_UInt32_random();
    ctx->eventId = (UA_ByteString){16, ctx->eventIdBuf};
    return UA_STATUSCODE_GOOD;
}

/* The SAO string is not always in the "normal form" that is the output of
 * UA_SimpleAttributeOperand_print. For example, we can have an implicit #Value
 * postfix or the path-browsenames prefixed with 0: for ns0. Also, for the
 * map-keys as QualifiedNames, we use the key-nsindex as the default nsindex for
 * the path.
 *
 * In order to compare with a non-normal-form SAO string, we decode and compare
 * the SAO directly. This is slower, so we try the normal form string-compare
 * first. */
static UA_Variant *
getEventFieldNonNormalForm(UA_Server *server, const UA_KeyValueMap *eventFields,
                           const UA_SimpleAttributeOperand *sao) {
    if(!eventFields)
        return NULL;

    UA_SimpleAttributeOperand keySao;
    for(size_t i = 0; i < eventFields->mapSize; i++) {
        UA_KeyValuePair *kvp = &eventFields->map[i];
        UA_StatusCode res =
            sao_parseWithDefaultNsIdx(&keySao, kvp->key.name,
                                      kvp->key.namespaceIndex);
        if(res != UA_STATUSCODE_GOOD)
            continue;
        UA_Boolean found = UA_SimpleAttributeOperand_equal(sao, &keySao);
        UA_SimpleAttributeOperand_clear(&keySao);
        if(found)
            return &kvp->value;
    }
    return NULL;
}

/* Can return an in-situ value. Check for UA_VARIANT_DATA_NODELETE. */
UA_StatusCode
resolveSAO(UA_FilterEvalContext *ctx, const UA_SimpleAttributeOperand *sao,
           UA_Variant *out) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_EventDescription *ed = &ctx->ed;
    const UA_Variant *found;
    UA_Byte pathBuf[512];
    UA_QualifiedName pathString = {0, {512, pathBuf}};
    static UA_NodeId baseEventTypeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEEVENTTYPE}};

    /* Copy into a mutable SAO */
    UA_SimpleAttributeOperand tmp_sao = *sao;

    /* Do the lookup without the index-range.
     * The index-range from the original sao is used later. */
    tmp_sao.indexRange = UA_STRING_NULL;

    /* Initially use the BaseEventTypeId if not defined explicitly.
     * If this does not resolve, we try again with i=0 (goto search again). */
    if(UA_NodeId_isNull(&tmp_sao.typeDefinitionId))
        tmp_sao.typeDefinitionId = baseEventTypeId;

 search_again:
    res = UA_SimpleAttributeOperand_print(&tmp_sao, &pathString.name);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Special Case: EventId (generated only once per Event, ignores the IndexRange) */
    if(UA_String_equal(&pathString.name, &mandatoryEventProperties[0])) {
        res = cacheEventId(ctx);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        UA_Variant_setScalar(out, &ctx->eventId, &UA_TYPES[UA_TYPES_BYTESTRING]);
        out->storageType = UA_VARIANT_DATA_NODELETE;
        return UA_STATUSCODE_GOOD;
    }

    /* Source 1: Use the SAO-string to look up from the user-defined key-value
     * map (and from the cache) */
    found = UA_KeyValueMap_get(ed->eventFields, pathString);
    if(!found)
        found = UA_KeyValueMap_get(&ctx->fieldCache, pathString);
    if(!found)
        found = getEventFieldNonNormalForm(ctx->server, ed->eventFields, &tmp_sao);
    if(found) {
        if(sao->indexRange.length == 0) {
            *out = *found;
            out->storageType = UA_VARIANT_DATA_NODELETE;
        } else {
            UA_NumericRange range;
            res = UA_NumericRange_parse(&range, sao->indexRange);
            if(res != UA_STATUSCODE_GOOD)
               return res;
            res = UA_Variant_copyRange(found, out, range);
            UA_free(range.dimensions);
        }
        return res;
    }

    /* Not found. Print the SAO again with BaseEventTypeId as the
     * TypeDefinitionId and try again. This removes any TypeDefinitionId prefix
     * from the printed SAO-string. */
    if(!UA_NodeId_equal(&tmp_sao.typeDefinitionId, &baseEventTypeId)) {
        tmp_sao.typeDefinitionId = baseEventTypeId;
        goto search_again;
    }

    /* Source 2: Read from the information model */
    res = readSAOfromEventInstance(ctx, sao, out);
    if(res == UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_GOOD;

    /* Source 3: Use a default for the mandatory fields of the BaseEventType.
     * Here we ignore the IndexRange. */
    UA_String_init(&tmp_sao.indexRange); /* No index range allowed */
    if(UA_String_equal(&pathString.name, &mandatoryEventProperties[1])) {
        /* EventType */
        return UA_Variant_setScalarCopy(out, &ed->eventType, &UA_TYPES[UA_TYPES_NODEID]);
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[2])) {
        /* SourceNode */
        return UA_Variant_setScalarCopy(out, &ed->sourceNode, &UA_TYPES[UA_TYPES_NODEID]);
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[3])) {
        /* SourceName. Read the DisplayName from the information model. This
         * uses the locale of the session. */
        UA_ReadValueId rvi;
        UA_ReadValueId_init(&rvi);
        rvi.nodeId = ed->sourceNode;
        rvi.attributeId = UA_ATTRIBUTEID_DISPLAYNAME;
        UA_DataValue dv = readWithSession(ctx->server, ctx->session, &rvi,
                                          UA_TIMESTAMPSTORETURN_NEITHER);
        if(dv.status != UA_STATUSCODE_GOOD) {
            res = dv.status;
            UA_DataValue_clear(&dv);
            return res;
        }
        if(dv.value.type != &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) {
            UA_DataValue_clear(&dv);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        UA_LocalizedText *displayName = (UA_LocalizedText*)dv.value.data;
        res = UA_Variant_setScalarCopy(out, &displayName->text, &UA_TYPES[UA_TYPES_STRING]);
        UA_DataValue_clear(&dv);
        return res;
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[4]) ||
              UA_String_equal(&pathString.name, &mandatoryEventProperties[5])) {
        /* Time / ReceiveTime */
        UA_EventLoop *el = ctx->server->config.eventLoop;
        UA_DateTime rcvTime = el->dateTime_now(el);
        return UA_Variant_setScalarCopy(out, &rcvTime, &UA_TYPES[UA_TYPES_DATETIME]);
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[6])) {
        /* Message */
        return UA_Variant_setScalarCopy(out, &ed->message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[7])) {
        /* Severity */
        return UA_Variant_setScalarCopy(out, &ed->severity, &UA_TYPES[UA_TYPES_UINT16]);
    }

    /* Not found, return an empty Variant */
    return UA_STATUSCODE_GOOD;
}

/***************************/
/* Where-Clause Evaluation */
/***************************/

/* Ternary Logic
 * -------------
 * Similar to SQL, OPC UA Queries use the K3 - Strong Kleene Logic that
 * considers ternary values true/false/null (unknown). Most operators resolve to
 * a ternary value. Some operators can resolve to a literal value (e.g. CAST). */

typedef enum {
    UA_TERNARY_FALSE = -1,
    UA_TERNARY_NULL = 0,
    UA_TERNARY_TRUE = 1
} UA_Ternary;

static UA_Ternary
UA_Ternary_and(UA_Ternary first, UA_Ternary second) {
    if(first == UA_TERNARY_FALSE || second == UA_TERNARY_FALSE)
        return UA_TERNARY_FALSE;
    if(first == UA_TERNARY_NULL || second == UA_TERNARY_NULL)
        return UA_TERNARY_NULL;
    return UA_TERNARY_TRUE;
}

static UA_Ternary
UA_Ternary_or(UA_Ternary first, UA_Ternary second) {
    if(first == UA_TERNARY_TRUE || second == UA_TERNARY_TRUE)
        return UA_TERNARY_TRUE;
    if(first == UA_TERNARY_NULL || second == UA_TERNARY_NULL)
        return UA_TERNARY_NULL;
    return UA_TERNARY_FALSE;
}

/* Part 4: The NOT operator always evaluates to NULL if applied to a NULL
 * operand. We simply swap true/false. */
static UA_Ternary
UA_Ternary_not(UA_Ternary v) {
    return (UA_Ternary)((int)v * -1);
}

static UA_Ternary v2t(const UA_Variant *v) {
    if(UA_Variant_isEmpty(v) || !UA_Variant_hasScalarType(v, &UA_TYPES[UA_TYPES_BOOLEAN]))
        return UA_TERNARY_NULL;
    UA_Boolean b = *(UA_Boolean*)v->data;
    return (b) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE;
}

static const UA_Boolean bFalse = false;
static const UA_Boolean bTrue  = true;

static UA_Variant t2v(UA_Ternary t) {
    UA_Variant v;
    UA_Variant_init(&v);
    switch(t) {
    case UA_TERNARY_FALSE:
        UA_Variant_setScalar(&v, (void*)(uintptr_t)&bFalse, &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_TERNARY_TRUE:
        UA_Variant_setScalar(&v, (void*)(uintptr_t)&bTrue, &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    default:
        return v;
    }
    v.storageType = UA_VARIANT_DATA_NODELETE;
    return v;
}

/* Type Casting Rules
 * ------------------
 * For comparison operations values from different datatypes can be implicitly
 * or explicitly cast. The standard defines rules to selected the target type
 * for casting and when implicit casts are possible. */

/* Defined in Part 4 Table 123 "Data Precedence Rules". Implicit casting is
 * always to the type of lower precedence value. */
static UA_Byte typePrecedence[UA_DATATYPEKINDS] = {
    12, 10, 11, 8, 9, 5, 6, 3, 4, 2, 1, 14, 255, 13, 255, 255, 16,
    15, 7, 18, 17, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
};

/* Type conversion table from the standard.
 * 0 -> Same Type, 1 -> Implicit Cast, 2 -> Only explicit Cast, -1 -> cast invalid */
static UA_SByte convertLookup[21][21] = {
    { 0, 1,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1},
    { 2, 0,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1},
    {-1,-1, 0,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
    {-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 0,-1, 2,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1},
    {-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1, 2,-1,-1, 1,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 0,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1},
    {-1,-1, 2,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 0, 1, 1,-1, 2,-1, 2,-1,-1, 2, 1, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 0, 1,-1, 2, 2, 2,-1,-1, 2, 2, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 0,-1, 2, 2, 2,-1,-1, 2, 2, 2,-1},
    {-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1, 0,-1,-1, 1,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 0,-1, 2,-1,-1, 1, 1, 1,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1,-1,-1, 0,-1,-1,-1, 2, 1, 1,-1},
    { 1, 1,-1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,-1, 0, 2, 2, 1, 1, 1,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 0,-1,-1,-1,-1,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 0,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 2, 1, 2,-1,-1, 0, 1, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 1, 1,-1, 2, 2, 2,-1,-1, 2, 0, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 1,-1, 2, 2, 2,-1,-1, 2, 2, 0,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0}
};

/* This array maps the index of the DataType-Kind to the index of the type
 * conversion matrix (255 -> not contained in the matrix) */
static UA_Byte convertLookupIndex[UA_DATATYPEKINDS] = {
    0,  12,  1,  8, 17,  9, 18, 10, 19,  6, 4,  14,  3,  7,  2,
    20, 11,  5, 13, 16, 15,255,255,255,255,255,255,255,255,255,255
};

/* Returns the target type for implicit cassting or NULL if no implicit casting
 * is possible */
static const UA_DataType *
implicitCastTargetType(const UA_DataType *t1, const UA_DataType *t2) {
    if(!t1 || t1 == t2)
        return t1;

    /* Get the type precedence. Return if no implicit casting is possible. */
    UA_Byte p1 = typePrecedence[t1->typeKind];
    UA_Byte p2 = typePrecedence[t2->typeKind];
    if(p1 == UA_BYTE_MAX || p2 == UA_BYTE_MAX)
        return NULL;

    /* Which is the target type based on the precedence rules? */
    const UA_DataType *targetType = (p1 < p2) ? t1 : t2;
    const UA_DataType *sourceType = (p1 < p2) ? t2 : t1;

    /* Lookup the casting rule */
    UA_Byte sourceIndex = convertLookupIndex[sourceType->typeKind];
    UA_Byte targetIndex = convertLookupIndex[targetType->typeKind];
    if(sourceIndex == UA_BYTE_MAX || targetIndex == UA_BYTE_MAX)
        return NULL;
    UA_SByte castingRule = convertLookup[sourceIndex][targetIndex];

    /* Is implicit casting allowed? */
    if(castingRule != 0 && castingRule != 1)
        return NULL;
    return targetType;
}

/* Cast Numerical
 * --------------
 * To reduce the number of cases we first "normalize" to either of
 * Int64/UInt64/Double. Then cast from there to the target type. This works for
 * all numericals (not only the implicit conversion).
 *
 * Numerical conversion rules from the standard:
 *
 * - If the conversion fails the result is a null value.
 * - Floating point values are rounded by adding 0.5 and truncating when they
 *   are converted to integer values.
 * - Converting a value that is outside the range of the target type causes a
 *   conversion error. */

#define UA_CAST_SIGNED(t, T)                                           \
    if(i < (UA_Int64)T##_MIN || i > (UA_Int64)T##_MAX) {               \
        UA_free(data);                                                 \
        return;                                                        \
    }                                                                  \
    *(t*)data = (t)i;                                                  \
    do { } while(0)

#define UA_CAST_UNSIGNED(t, T)                                         \
    if(u > T##_MAX) {                                                  \
        UA_free(data);                                                 \
        return;                                                        \
    }                                                                  \
    *(t*)data = (t)u;                                                  \
    do { } while(0)

#define UA_CAST_FLOAT(t, T)                                            \
    if(f + 0.5 < (UA_Double)T##_MIN || f + 0.5 > (UA_Double)T##_MAX) { \
        UA_free(data);                                                 \
        return;                                                        \
    }                                                                  \
    *(t*)data = (t)(f + 0.5);                                          \
    do { } while(0)

/* We can cast between any numerical type. So this can be reused for explicit casting. */
static void
castNumerical(const UA_Variant *in, const UA_DataType *type, UA_Variant *out) {
    UA_assert(UA_Variant_isScalar(in));
    UA_Variant_init(out); /* Set to null value */

    UA_Int64  i = 0;
    UA_UInt64 u = 0;
    UA_Double f = 0.0;

    const UA_DataTypeKind ink = (UA_DataTypeKind)in->type->typeKind;
    switch(ink) {
    case UA_DATATYPEKIND_SBYTE:  i = *(UA_SByte*)in->data; break;
    case UA_DATATYPEKIND_INT16:  i = *(UA_Int16*)in->data; break;
    case UA_DATATYPEKIND_INT32:  i = *(UA_Int32*)in->data; break;
    case UA_DATATYPEKIND_INT64:  i = *(UA_Int64*)in->data; break;
    case UA_DATATYPEKIND_BYTE: /* or */
    case UA_DATATYPEKIND_BOOLEAN: u = *(UA_Byte*)in->data; break;
    case UA_DATATYPEKIND_UINT16:  u = *(UA_UInt16*)in->data; break;
    case UA_DATATYPEKIND_UINT32: /* or */
    case UA_DATATYPEKIND_STATUSCODE: u = *(UA_UInt32*)in->data; break;
    case UA_DATATYPEKIND_UINT64: u = *(UA_UInt64*)in->data; break;
    case UA_DATATYPEKIND_FLOAT:  f = *(UA_Float*)in->data; break;
    case UA_DATATYPEKIND_DOUBLE: f = *(UA_Double*)in->data; break;
    default: return;
    }

    void *data = UA_new(type);
    if(!data)
        return;

    if(ink == UA_DATATYPEKIND_SBYTE || ink == UA_DATATYPEKIND_INT16 ||
       ink == UA_DATATYPEKIND_INT32 || ink == UA_DATATYPEKIND_INT64) {
        /* Cast from signed */
        switch(type->typeKind) {
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_SIGNED(UA_SByte, UA_SBYTE); break;
        case UA_DATATYPEKIND_INT16:  UA_CAST_SIGNED(UA_Int16, UA_INT16); break;
        case UA_DATATYPEKIND_INT32:  UA_CAST_SIGNED(UA_Int32, UA_INT32); break;
        case UA_DATATYPEKIND_INT64:  *(UA_Int64*)data = i; break;
        case UA_DATATYPEKIND_BYTE:   UA_CAST_SIGNED(UA_Byte, UA_BYTE); break;
        case UA_DATATYPEKIND_UINT16: UA_CAST_SIGNED(UA_UInt16, UA_UINT16); break;
        case UA_DATATYPEKIND_UINT32: UA_CAST_SIGNED(UA_UInt32, UA_UINT32); break;
        case UA_DATATYPEKIND_UINT64: UA_CAST_SIGNED(UA_UInt64, UA_UINT64); break;
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)i; break;
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)i; break;
        default:
            UA_free(data);
            return;
        }
    } else if(ink == UA_DATATYPEKIND_BYTE   || ink == UA_DATATYPEKIND_UINT16 ||
              ink == UA_DATATYPEKIND_UINT32 || ink == UA_DATATYPEKIND_UINT64) {
        /* Cast from unsigned */
        switch(type->typeKind) {
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_UNSIGNED(UA_SByte, UA_SBYTE); break;
        case UA_DATATYPEKIND_INT16:  UA_CAST_UNSIGNED(UA_Int16, UA_INT16); break;
        case UA_DATATYPEKIND_INT32:  UA_CAST_UNSIGNED(UA_Int32, UA_INT32); break;
        case UA_DATATYPEKIND_INT64:  UA_CAST_UNSIGNED(UA_Int64, UA_INT64); break;
        case UA_DATATYPEKIND_BYTE:   UA_CAST_UNSIGNED(UA_Byte, UA_BYTE); break;
        case UA_DATATYPEKIND_UINT16: UA_CAST_UNSIGNED(UA_UInt16, UA_UINT16); break;
        case UA_DATATYPEKIND_UINT32: UA_CAST_UNSIGNED(UA_UInt32, UA_UINT32); break;
        case UA_DATATYPEKIND_UINT64: *(UA_UInt64*)data = u; break;
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)u; break;
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)u; break;
        default:
            UA_free(data);
            return;
        }
    } else {
        /* Cast from float */
        if(f != f) {
            /* NaN cannot be cast */
            UA_free(data);
            return;
        }
        switch(type->typeKind) {
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_FLOAT(UA_SByte, UA_SBYTE); break;
        case UA_DATATYPEKIND_INT16:  UA_CAST_FLOAT(UA_Int16, UA_INT16); break;
        case UA_DATATYPEKIND_INT32:  UA_CAST_FLOAT(UA_Int32, UA_INT32); break;
        case UA_DATATYPEKIND_INT64:  UA_CAST_FLOAT(UA_Int64, UA_INT64); break;
        case UA_DATATYPEKIND_BYTE:   UA_CAST_FLOAT(UA_Byte, UA_BYTE); break;
        case UA_DATATYPEKIND_UINT16: UA_CAST_FLOAT(UA_UInt16, UA_UINT16); break;
        case UA_DATATYPEKIND_UINT32: UA_CAST_FLOAT(UA_UInt32, UA_UINT32); break;
        case UA_DATATYPEKIND_UINT64: UA_CAST_FLOAT(UA_UInt64, UA_UINT64); break;
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)f; break;
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)f; break;
        default:
            UA_free(data);
            return;
        }
    }

    UA_Variant_setScalar(out, data, type);
}

/* Implicit Casting
 * ---------------- */

static UA_INLINE UA_Byte uppercase(UA_Byte in) { return in | 32; }

static UA_StatusCode
castImplicitFromString(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    if(outType == &UA_TYPES[UA_TYPES_BOOLEAN]) {
        /* String -> Boolean
         *
         * Part 4 says: String values containing "true", "false", "1" or "0"
         * can be converted to Boolean values. Other string values cause a
         * conversion error. In this case Strings are case-insensitive. */
        UA_Boolean b;
        const UA_String *inStr = (const UA_String*)in->data;
        if(inStr->length == 1 && inStr->data[0] == '0') {
            b = false;
        } else if(inStr->length == 1 && inStr->data[0] == '1') {
            b = true;
        } else if(inStr->length == 4 &&
                  uppercase(inStr->data[0])== 'T' && uppercase(inStr->data[1])== 'R' &&
                  uppercase(inStr->data[2])== 'U' && uppercase(inStr->data[3])== 'E') {
            b = true;
        } else if(inStr->length == 5              && uppercase(inStr->data[0])== 'F' &&
                  uppercase(inStr->data[1])== 'A' && uppercase(inStr->data[2])== 'L' &&
                  uppercase(inStr->data[3])== 'S' && uppercase(inStr->data[4])== 'E') {
            b = false;
        } else {
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }
        return UA_Variant_setScalarCopy(out, &b, outType);
    } else if(outType == &UA_TYPES[UA_TYPES_GUID]) {
        /* String -> Guid */
        UA_Guid guid;
        res = UA_Guid_parse(&guid, *(UA_String*)in->data);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        return UA_Variant_setScalarCopy(out, &guid, outType);
    }

#ifdef UA_ENABLE_JSON_ENCODING
    /* String -> Numerical, uses the JSON decoding */
    else if(UA_DataType_isNumeric(outType)) {
        void *outData = UA_new(outType);
        if(!outData)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_decodeJson((const UA_ByteString*)in->data, outData, outType, NULL);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free(outData);
            return res;
        }
        UA_Variant_setScalar(out, outData, outType);
        return UA_STATUSCODE_GOOD;
    }
#endif

    /* No implicit casting possible */
    return UA_STATUSCODE_BADTYPEMISMATCH;
}

static UA_StatusCode
castImplicit(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out) {
    /* Of the input is empty, casting results in a NULL value */
    if(UA_Variant_isEmpty(in)) {
        UA_Variant_init(out);
        return UA_STATUSCODE_GOOD;
    }

    /* TODO: We only support scalar values for now */
    if(!UA_Variant_isScalar(in))
        return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;

    /* No casting necessary */
    if(in->type == outType) {
        *out = *in;
        out->storageType = UA_VARIANT_DATA_NODELETE;
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(in->type->typeKind) {
    case UA_DATATYPEKIND_EXPANDEDNODEID: {
        /* ExpandedNodeId -> String */
        if(outType != &UA_TYPES[UA_TYPES_STRING])
            break;
        UA_String *outStr = UA_String_new();
        if(!outStr)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_ExpandedNodeId_print((const UA_ExpandedNodeId*)in->data, outStr);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free(outStr);
            break;
        }
        UA_Variant_setScalar(out, outStr, outType);
        break;
    }

    case UA_DATATYPEKIND_NODEID: {
        if(outType == &UA_TYPES[UA_TYPES_STRING]) {
            /* NodeId -> String */
            UA_String *outStr = UA_String_new();
            if(!outStr)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            res = UA_NodeId_print((const UA_NodeId*)in->data, outStr);
            if(res != UA_STATUSCODE_GOOD) {
                UA_free(outStr);
                break;
            }
            UA_Variant_setScalar(out, outStr, outType);
        } else if(outType == &UA_TYPES[UA_TYPES_EXPANDEDNODEID]) {
            /* NodeId -> ExpandedNodeId */
            UA_ExpandedNodeId *eid = UA_ExpandedNodeId_new();
            if(!eid)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            res = UA_NodeId_copy((const UA_NodeId*)in->data, &eid->nodeId);
            if(res != UA_STATUSCODE_GOOD) {
                UA_free(eid);
                break;
            }
            UA_Variant_setScalar(out, eid, outType);
        }
        break;
    }

    case UA_DATATYPEKIND_STRING:
        res = castImplicitFromString(in, outType, out);
        break;

    case UA_DATATYPEKIND_LOCALIZEDTEXT: {
        if(outType != &UA_TYPES[UA_TYPES_STRING])
            break;
        /* LocalizedText -> String */
        UA_LocalizedText *inLT = (UA_LocalizedText*)in->data;
        res = UA_Variant_setScalarCopy(out, &inLT->text, outType);
        break;
    }

    case UA_DATATYPEKIND_QUALIFIEDNAME: {
        UA_QualifiedName *inQN = (UA_QualifiedName*)in->data;
        if(outType == &UA_TYPES[UA_TYPES_STRING]) {
            /* QualifiedName -> String */
            res = UA_Variant_setScalarCopy(out, &inQN->name, outType);
        } else if(outType == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) {
            /* QualifiedName -> LocalizedText */
            UA_LocalizedText lt;
            lt.text = inQN->name;
            lt.locale = UA_STRING_NULL;
            res = UA_Variant_setScalarCopy(out, &lt, outType);
        }
        break;
    }

    default:
        /* Try casting between numericals (also works for Boolean and StatusCode
         * input). The conversion can fail if the limits of the output type are
         * exceeded and then results in a NULL value. */
        castNumerical(in, outType, out);
    }

    return res;
}

/* Filter Evaluation
 * ----------------- */

static UA_StatusCode
resolveOperand(UA_FilterEvalContext *ctx, UA_ExtensionObject *op, UA_Variant *out) {
    if(op->encoding != UA_EXTENSIONOBJECT_DECODED &&
       op->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
        return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;

    /* Result of an operator that was evaluated prior */
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) {
        UA_ElementOperand *eo = (UA_ElementOperand*)op->content.decoded.data;
        *out = ctx->operatorResults[eo->index];
        out->storageType = UA_VARIANT_DATA_NODELETE;
        return UA_STATUSCODE_GOOD;
    }

    /* Literal value */
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_LITERALOPERAND]) {
        UA_LiteralOperand *lo = (UA_LiteralOperand*)op->content.decoded.data;
        *out = lo->value;
        out->storageType = UA_VARIANT_DATA_NODELETE;
        return UA_STATUSCODE_GOOD;
    }

    /* SimpleAttributeOperand with a BrowsePath */
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]) {
        UA_SimpleAttributeOperand *sao =
            (UA_SimpleAttributeOperand*)op->content.decoded.data;
        return resolveSAO(ctx, sao, out);
    }

    return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
}

static UA_StatusCode
ofTypeOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
    UA_assert(elm->filterOperandsSize == 1);

    /* Get the operand. Must be a literal NodeId */
    UA_Variant *op0 = &ctx->operandStack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    if(res != UA_STATUSCODE_GOOD || !UA_Variant_hasScalarType(op0, &UA_TYPES[UA_TYPES_NODEID]))
        return UA_STATUSCODE_BADFILTEROPERANDINVALID;
    const UA_NodeId *operandTypeId = (const UA_NodeId *)op0->data;

    /* Read the /EventType event field */
    static UA_QualifiedName eventTypeName = {0, UA_STRING_STATIC("EventType")};
    UA_SimpleAttributeOperand sao;
    UA_SimpleAttributeOperand_init(&sao);
    sao.attributeId = UA_ATTRIBUTEID_VALUE;
    sao.browsePath = &eventTypeName;
    sao.browsePathSize = 1;
    UA_Variant eventType;
    UA_Variant_init(&eventType);
    res = resolveSAO(ctx, &sao, &eventType);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    if(!UA_Variant_hasScalarType(&eventType, &UA_TYPES[UA_TYPES_NODEID])) {
        UA_Variant_clear(&eventType);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Is the /EventType a subtype of the requested type? */
    UA_Boolean ofType =
        isNodeInTree_singleRef(ctx->server, (UA_NodeId*)eventType.data, operandTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE);
    ctx->operatorResults[index] = t2v(ofType ? UA_TERNARY_TRUE : UA_TERNARY_FALSE);
    UA_Variant_clear(&eventType);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
andOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
    UA_assert(elm->filterOperandsSize == 2);
    UA_Variant *op0 = &ctx->operandStack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    UA_Variant *op1 = &ctx->operandStack[ctx->top++];
    res = resolveOperand(ctx, &elm->filterOperands[1], op1);
    UA_CHECK_STATUS(res, return res);
    ctx->operatorResults[index] = t2v(UA_Ternary_and(v2t(op0), v2t(op1)));
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
orOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
    UA_assert(elm->filterOperandsSize == 2);
    UA_Variant *op0 = &ctx->operandStack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    UA_Variant *op1 = &ctx->operandStack[ctx->top++];
    res = resolveOperand(ctx, &elm->filterOperands[1], op1);
    UA_CHECK_STATUS(res, return res);
    ctx->operatorResults[index] = t2v(UA_Ternary_or(v2t(op0), v2t(op1)));
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
notOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
    UA_assert(elm->filterOperandsSize == 1);
    UA_Variant *op0 = &ctx->operandStack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    ctx->operatorResults[index] = t2v(UA_Ternary_not(v2t(op0)));
    return UA_STATUSCODE_GOOD;
}

/* Resolves the operands and casts them implicitly to the same type. The result
 * is set at &ctx->operandStack[ctx->top] (for the initial value of top). */
static UA_StatusCode
castResolveOperands(UA_FilterEvalContext *ctx, size_t index, UA_Boolean setError) {
    /* Enough space on the operand stack left? */
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
    if(ctx->top + elm->filterOperandsSize > UA_EVENTFILTER_MAXOPERANDS)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Resolve all operands */
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < elm->filterOperandsSize; i++) {
        res = resolveOperand(ctx, &elm->filterOperands[i], &ctx->operandStack[ctx->top++]);
        UA_CHECK_STATUS(res, return res);
    }
    UA_assert(ctx->top > 0); /* Assume the operand stack is no longer empty */

    /* Get the datatype for casting */
    const UA_DataType *targetType = ctx->operandStack[0].type;
    for(size_t pos = 1; pos < ctx->top; pos++) {
        if(targetType)
            targetType = implicitCastTargetType(targetType, ctx->operandStack[pos].type);
        if(!targetType)
            return UA_STATUSCODE_BADFILTEROPERANDINVALID;
    }

    /* Cast the operands. Put the result in the same location on the operand stack. */
    for(size_t pos = 0; pos < ctx->top; pos++) {
        UA_Variant orig = ctx->operandStack[pos];
        res = castImplicit(&orig, targetType, &ctx->operandStack[pos]);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        if(ctx->operandStack[pos].data == orig.data) {
            /* Reuse the storage type of the original data if the variant is
             * identical or only the type has changed */
            ctx->operandStack[pos].storageType = orig.storageType;
        } else {
            UA_Variant_clear(&orig); /* Fresh allocation of the cast variant. Clean up. */
        }
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
compareOperator(UA_FilterEvalContext *ctx, size_t index, UA_FilterOperator op) {
    UA_assert(ctx->filter.whereClause.elements[index].filterOperandsSize == 2);

    /* Resolve and cast the operands. A failed casting results in FALSE. Note
     * that operands could cast to NULL. */
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
    UA_StatusCode res = castResolveOperands(ctx, index, false);
    if(res != UA_STATUSCODE_GOOD || !ctx->operandStack[0].type ||
       ctx->operandStack[0].type != ctx->operandStack[1].type) {
        ctx->operatorResults[index] = t2v(UA_TERNARY_FALSE);
        return UA_STATUSCODE_GOOD;
    }
    UA_assert(ctx->top == 2); /* Assume the operand stack is no longer empty */

    /* The equals operator is always possible. For the other comparisons it has
     * to be an ordered type: Numerical, Boolean, StatusCode or DateTime. */
    const UA_DataType *type = ctx->operandStack[0].type;
    if(op != UA_FILTEROPERATOR_EQUALS && !UA_DataType_isNumeric(type) &&
       type->typeKind != UA_DATATYPEKIND_BOOLEAN &&
       type->typeKind != UA_DATATYPEKIND_STATUSCODE &&
       type->typeKind != UA_DATATYPEKIND_DATETIME)
        return UA_STATUSCODE_BADFILTEROPERANDINVALID;

    /* Compute the order */
    UA_Order eq = UA_order(ctx->operandStack[0].data, ctx->operandStack[1].data, type);
    UA_Ternary operatorResult = UA_TERNARY_FALSE;
    switch(op) {
    case UA_FILTEROPERATOR_EQUALS:
    default:
        if(eq == UA_ORDER_EQ)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_GREATERTHAN:
        if(eq == UA_ORDER_MORE)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_LESSTHAN:
        if(eq == UA_ORDER_LESS)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_GREATERTHANOREQUAL:
        if(eq == UA_ORDER_MORE || eq == UA_ORDER_EQ)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_LESSTHANOREQUAL:
        if(eq == UA_ORDER_LESS || eq == UA_ORDER_EQ)
            operatorResult = UA_TERNARY_TRUE;
        break;
    }

    /* Set result as a literal value */
    ctx->operatorResults[index] = t2v(operatorResult);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
equalsOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_EQUALS);
}

static UA_StatusCode
gtOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_GREATERTHAN);
}

static UA_StatusCode
ltOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_LESSTHAN);
}

static UA_StatusCode
gteOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_GREATERTHANOREQUAL);
}

static UA_StatusCode
lteOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_LESSTHANOREQUAL);
}

static UA_StatusCode
bitwiseOperator(UA_FilterEvalContext *ctx, size_t index, UA_FilterOperator op) {
    UA_assert(ctx->filter.whereClause.elements[index].filterOperandsSize == 2);

    /* Resolve and cast the operands. Note that operands could cast to NULL. */
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
    UA_StatusCode res = castResolveOperands(ctx, index, true);
    UA_CHECK_STATUS(res, return res);
    UA_assert(ctx->top == 2); /* Assume we have two elements */

    /* Operands can cast to NULL */
    const UA_DataType *type = ctx->operandStack[0].type;
    if(!type || !UA_DataType_isNumeric(type) ||
       ctx->operandStack[0].type != ctx->operandStack[1].type)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Copy the casted literal to the result */
    res = UA_Variant_copy(&ctx->operandStack[0], &ctx->operatorResults[index]);
    UA_CHECK_STATUS(res, return res);

    /* Do the bitwise operation on the result data */
    UA_Byte *bytesOut = (UA_Byte*)ctx->operatorResults[index].data;
    const UA_Byte *bytes2 = (const UA_Byte*)ctx->operandStack[1].data;
    for(size_t i = 0; i < type->memSize; i++) {
        if(op == UA_FILTEROPERATOR_BITWISEAND)
            bytesOut[i] = bytesOut[i] & bytes2[i];
        else
            bytesOut[i] = bytesOut[i] | bytes2[i];
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
bitwiseAndOperator(UA_FilterEvalContext *ctx, size_t index) {
    return bitwiseOperator(ctx, index, UA_FILTEROPERATOR_BITWISEAND);
}

static UA_StatusCode
bitwiseOrOperator(UA_FilterEvalContext *ctx, size_t index) {
    return bitwiseOperator(ctx, index, UA_FILTEROPERATOR_BITWISEOR);
}

static UA_StatusCode
betweenOperator(UA_FilterEvalContext *ctx, size_t index) {
    UA_assert(ctx->filter.whereClause.elements[index].filterOperandsSize == 3);

    /* If no implicit conversion is available and the operands are of different
     * types, the particular result is FALSE. */
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
    UA_StatusCode res = castResolveOperands(ctx, index, false);
    if(res != UA_STATUSCODE_GOOD) {
        ctx->operatorResults[index] = t2v(UA_TERNARY_FALSE);
        return UA_STATUSCODE_GOOD;
    }
    UA_assert(ctx->top == 3); /* Assume we have three elements */

    /* The casting can result in NULL values or a non-numerical type */
    const UA_DataType *type = ctx->operandStack[0].type;
    if(!type || !UA_DataType_isNumeric(type) ||
       type != ctx->operandStack[1].type || type != ctx->operandStack[2].type)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_Order o1 = UA_order(ctx->operandStack[0].data, ctx->operandStack[1].data, type);
    UA_Order o2 = UA_order(ctx->operandStack[0].data, ctx->operandStack[2].data, type);
    UA_Ternary comp = ((o1 == UA_ORDER_MORE || o1 == UA_ORDER_EQ) &&
                       (o2 == UA_ORDER_LESS || o2 == UA_ORDER_EQ)) ?
        UA_TERNARY_TRUE : UA_TERNARY_FALSE;

    ctx->operatorResults[index] = t2v(comp);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
inListOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
    UA_assert(elm->filterOperandsSize >= 2);
    UA_Boolean found = false;
    UA_Variant *op0 = &ctx->operandStack[ctx->top++];
    UA_Variant *op1 = &ctx->operandStack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    for(size_t i = 1; i < elm->filterOperandsSize && !found; i++) {
        res = resolveOperand(ctx, &elm->filterOperands[i], op1);
        if(res != UA_STATUSCODE_GOOD)
            continue;
        if(op0->type == op1->type && UA_equal(op0->data, op1->data, op0->type))
            found = true;
        UA_Variant_clear(op1);
    }
    ctx->operatorResults[index] = t2v((found) ? UA_TERNARY_TRUE: UA_TERNARY_FALSE);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
isNullOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
    UA_assert(elm->filterOperandsSize == 1);
    UA_Variant *op0 = &ctx->operandStack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    ctx->operatorResults[index] =
        t2v(UA_Variant_isEmpty(op0) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
notImplementedOperator(UA_FilterEvalContext *ctx, size_t index) {
    return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
}

typedef struct {
    UA_StatusCode (*operatorMethod)(UA_FilterEvalContext *ctx, size_t index);
    UA_Byte minOperatorCount;
    UA_Byte maxOperatorCount;
} UA_FilterOperatorJumptableElement;

static const UA_FilterOperatorJumptableElement operatorJumptable[18] = {
    {equalsOperator, 2, 2},
    {isNullOperator, 1, 1},
    {gtOperator, 2, 2},
    {ltOperator, 2, 2},
    {gteOperator, 2, 2},
    {lteOperator, 2, 2},
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* like */
    {notOperator, 1, 1},
    {betweenOperator, 3, 3},
    {inListOperator, 2, UA_EVENTFILTER_MAXOPERANDS},
    {andOperator, 2, 2},
    {orOperator, 2, 2},
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* cast */
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* in view */
    {ofTypeOperator, 1, 1},
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* related to */
    {bitwiseAndOperator, 2, 2},
    {bitwiseOrOperator, 2, 2}
};

/* Evaluate content filter, exported only for unit testing */
UA_StatusCode
evaluateWhereClause(UA_FilterEvalContext *ctx) {
    UA_LOCK_ASSERT(&ctx->server->serviceMutex);

    /* An empty filter always succeeds */
    if(ctx->filter.whereClause.elementsSize == 0)
        return UA_STATUSCODE_GOOD;

    /* Pacify some compilers by initializing the first result */
    UA_assert(ctx->top == 0);
    UA_Variant_init(&ctx->operatorResults[0]);

    /* Evaluate the filter. Iterate backwards over the filter elements and
     * resolve each. This ensures that all element-index operands point to an
     * evaluated element. */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_ContentFilter *cf = &ctx->filter.whereClause;
    for(size_t i = cf->elementsSize - 1; i < cf->elementsSize; i--) {
        UA_ContentFilterElement *cfe = &cf->elements[i];
        res = operatorJumptable[cfe->filterOperator].operatorMethod(ctx, i);
        /* Clean up the operand stack */
        for(size_t j = 0; j < ctx->top; j++)
            UA_Variant_clear(&ctx->operandStack[j]);
        ctx->top = 0;
        if(res != UA_STATUSCODE_GOOD)
            break;
    }

    /* The filter matches if the operator at the first position evaluates to TRUE */
    if(res == UA_STATUSCODE_GOOD && v2t(&ctx->operatorResults[0]) != UA_TERNARY_TRUE)
        res = UA_STATUSCODE_BADNOMATCH;

    /* Clean up the results stack */
    for(size_t i = 0; i < cf->elementsSize; i++)
        UA_Variant_clear(&ctx->operatorResults[i]);
    return res;
}

/*****************************************/
/* Validation of Filters during Creation */
/*****************************************/

/* Initial select clause validation. The following checks are currently performed:
 * - Check if the TypeDefinitionId or BrowsePath of any clause is NULL
 * - Check if the EventType is a subtype of BaseEventType
 * - Check if the AttributeId is valid
 * - Check if the BrowsePath contains null
 * - Check if the IndexRange is defined and if it is parseable
 * - Check if the AttributeId is value when an IndexRange is defined */
UA_StatusCode
UA_SimpleAttributeOperandValidation(UA_Server *server,
                                    const UA_SimpleAttributeOperand *sao) {
    /* TypeDefinition is not NULL? */
    if(UA_NodeId_isNull(&sao->typeDefinitionId))
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;

    /* EventType is a subtype of BaseEventType? */
    UA_NodeId baseEventTypeId = UA_NS0ID(BASEEVENTTYPE);
    if(!isNodeInTree_singleRef(server, &sao->typeDefinitionId, &baseEventTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;

    /* AttributeId is valid ? */
    if(sao->attributeId == 0 || sao->attributeId >= 28)
        return UA_STATUSCODE_BADATTRIBUTEIDINVALID;

    /* If the BrowsePath is empty, the Node is the instance of the
     * TypeDefinition. (Part 4, 7.4.4.5) */
    if(sao->browsePathSize > 0) {
        /* BrowsePath contains empty BrowseNames? */
        for(size_t j = 0; j < sao->browsePathSize; ++j) {
            if(UA_QualifiedName_isNull(&sao->browsePath[j]))
                return UA_STATUSCODE_BADBROWSENAMEINVALID;
        }

        /* Part 4: If the SimpleAttributeOperand is used in an EventFilter and
         * the typeDefinitionId is BaseEventType the Server shall evaluate the
         * browsePath without considering the typeDefinitionId. */
        if(!UA_NodeId_equal(&baseEventTypeId, &sao->typeDefinitionId)) {
            /* Part 4: The TypeDefinitionNode restricts the operand to instances
             * of the TypeDefinitionNode or one of its subtypes.
             * First get the list of subtypes from event type (including the
             * event type itself). */
            UA_ReferenceTypeSet reftypes_interface =
                UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
            UA_ExpandedNodeId *childTypeNodes = NULL;
            size_t childTypeNodesSize = 0;
            UA_StatusCode res =
                browseRecursive(server, 1, &sao->typeDefinitionId, UA_BROWSEDIRECTION_FORWARD,
                                &reftypes_interface, UA_NODECLASS_OBJECTTYPE, true,
                                &childTypeNodesSize, &childTypeNodes);
            if(res != UA_STATUSCODE_GOOD)
                return UA_STATUSCODE_BADATTRIBUTEIDINVALID;

            /* Is the browse path valid for one of the event types? */
            UA_Boolean subTypeContainField = false;
            for(size_t j = 0; j < childTypeNodesSize && !subTypeContainField; j++) {
                UA_BrowsePathResult bpr =
                    browseSimplifiedBrowsePath(server, childTypeNodes[j].nodeId,
                                               sao->browsePathSize, sao->browsePath);

                if(bpr.statusCode == UA_STATUSCODE_GOOD && bpr.targetsSize > 0)
                    subTypeContainField = true;
                UA_BrowsePathResult_clear(&bpr);
            }

            /* Clean up and return an error if not found */
            UA_Array_delete(childTypeNodes, childTypeNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
            if(!subTypeContainField)
                return UA_STATUSCODE_BADNODEIDUNKNOWN;
        }
    }

    /* IndexRange is defined ? */
    if(!UA_String_isEmpty(&sao->indexRange)) {
        UA_NumericRange numericRange = UA_NUMERICRANGE("");
        if(UA_NumericRange_parse(&numericRange, sao->indexRange) != UA_STATUSCODE_GOOD)
            return UA_STATUSCODE_BADINDEXRANGEINVALID;
        UA_free(numericRange.dimensions);

        /* AttributeId has to be a value if an IndexRange is defined */
        if(sao->attributeId != UA_ATTRIBUTEID_VALUE)
            return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    return UA_STATUSCODE_GOOD;
}

/* Initial content filter (where clause) check. Current checks:
 * - Number of operands for each (supported) operator
 * - ElementOperands point forward only */
UA_ContentFilterElementResult
UA_ContentFilterElementValidation(UA_Server *server, size_t operatorIndex,
                                  size_t operatorsCount,
                                  const UA_ContentFilterElement *ef) {
    /* Initialize the result structure */
    UA_ContentFilterElementResult er;
    UA_ContentFilterElementResult_init(&er);
    er.operandStatusCodes = (UA_StatusCode *)
        UA_Array_new(ef->filterOperandsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
    if(!er.operandStatusCodes) {
        er.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return er;
    }
    er.operandStatusCodesSize = ef->filterOperandsSize;

    /* Is the operator in the defined range? Test this before the following
     * jumptable lookup. */
    if(ef->filterOperator < 0 || ef->filterOperator > UA_FILTEROPERATOR_BITWISEOR) {
        er.statusCode = UA_STATUSCODE_BADEVENTFILTERINVALID;
        return er;
    }

    /* Number of operands supported for the operator? */
    if(ef->filterOperandsSize < operatorJumptable[ef->filterOperator].minOperatorCount ||
       ef->filterOperandsSize > operatorJumptable[ef->filterOperator].maxOperatorCount) {
        er.statusCode = UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH;
        return er;
    }

    /* Generic validation of the operands */
    for(size_t i = 0; i < ef->filterOperandsSize; i++) {
        /* Must be a decoded ExtensionObject */
        UA_ExtensionObject *op = &ef->filterOperands[i];
        if(op->encoding != UA_EXTENSIONOBJECT_DECODED &&
           op->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
            er.operandStatusCodes[i] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            return er;
        }

        /* Supported type and conforming to the rules? */
        if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) {
            /* Part 4, 7.4.4.2 defines conditions for Element Operands: An index
             * is considered valid if its value is greater than the element
             * index it is part of and it does not Reference a non-existent
             * element. Clients shall construct filters in this way to avoid
             * circular and invalid References. */
            UA_ElementOperand *eo = (UA_ElementOperand *)op->content.decoded.data;
            if(eo->index <= operatorIndex || eo->index >= operatorsCount) {
                er.operandStatusCodes[i] = UA_STATUSCODE_BADINDEXRANGEINVALID;
                er.statusCode = UA_STATUSCODE_BADINDEXRANGEINVALID;
                return er;
            }
        } else if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]) {
            er.operandStatusCodes[i] = UA_STATUSCODE_BADNOTSUPPORTED;
            er.statusCode = UA_STATUSCODE_BADFILTERNOTALLOWED;
            return er;
        } else if(op->content.decoded.type != &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND] &&
                  op->content.decoded.type != &UA_TYPES[UA_TYPES_LITERALOPERAND]) {
            er.operandStatusCodes[i] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            return er;
        }
    }

    /* Specific validations for different operators */
    switch(ef->filterOperator) {
        case UA_FILTEROPERATOR_INVIEW:
        case UA_FILTEROPERATOR_RELATEDTO:
            /* Not allowed for event WhereClause according to 7.17.3 in Part 4 */
            er.statusCode = UA_STATUSCODE_BADEVENTFILTERINVALID;
            break;

        case UA_FILTEROPERATOR_EQUALS:
        case UA_FILTEROPERATOR_GREATERTHAN:
        case UA_FILTEROPERATOR_LESSTHAN:
        case UA_FILTEROPERATOR_GREATERTHANOREQUAL:
        case UA_FILTEROPERATOR_LESSTHANOREQUAL:
        case UA_FILTEROPERATOR_BITWISEAND:
        case UA_FILTEROPERATOR_BITWISEOR:
        case UA_FILTEROPERATOR_BETWEEN:
        case UA_FILTEROPERATOR_INLIST:
        case UA_FILTEROPERATOR_AND:
        case UA_FILTEROPERATOR_OR:
        case UA_FILTEROPERATOR_ISNULL:
        case UA_FILTEROPERATOR_NOT:
            break;

        case UA_FILTEROPERATOR_OFTYPE: {
            /* Make sure the operand is a NodeId literal */
            UA_ExtensionObject *o = &ef->filterOperands[0];
            UA_LiteralOperand *lo = (UA_LiteralOperand *)o->content.decoded.data;
            if(o->content.decoded.type != &UA_TYPES[UA_TYPES_LITERALOPERAND] ||
               !UA_Variant_hasScalarType(&lo->value, &UA_TYPES[UA_TYPES_NODEID])) {
                er.operandStatusCodes[0] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                break;
            }

            /* Make sure the operand is a subtype of BaseEventType */
            UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
            if(!isNodeInTree_singleRef(server, (UA_NodeId *)lo->value.data, &baseEventTypeId,
                                       UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
                er.operandStatusCodes[0] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                break;
            }
            break;
        }

        case UA_FILTEROPERATOR_LIKE:
        case UA_FILTEROPERATOR_CAST:
            er.statusCode = UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
            break;

        default:
            er.statusCode = UA_STATUSCODE_BADFILTEROPERATORINVALID;
            break;
    }
    return er;
}

/*************************/
/* Create Event Instance */
/*************************/

UA_StatusCode
evaluateSelectClause(UA_FilterEvalContext *ctx, UA_EventFieldList *efl) {
    /* Nothing to do */
    if(ctx->filter.selectClausesSize == 0)
        return UA_STATUSCODE_GOOD;

    /* Allocate the event fields list */
    efl->eventFields = (UA_Variant*)
        UA_calloc(ctx->filter.selectClausesSize, sizeof(UA_Variant));
    if(!efl->eventFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    efl->eventFieldsSize = ctx->filter.selectClausesSize;

    /* Resolve the select clauses */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < ctx->filter.selectClausesSize; i++) {
        const UA_SimpleAttributeOperand *sao = &ctx->filter.selectClauses[i];
        UA_Variant *field = &efl->eventFields[i];
        res |= resolveSAO(ctx, sao, field);

        /* Ensure a deep copy */
        if(field->storageType == UA_VARIANT_DATA_NODELETE) {
            UA_Variant tmp_val;
            UA_StatusCode res_ign = UA_Variant_copy(field, &tmp_val);
            (void)res_ign; /* Ignore the result - returns an empty variant if copying fails */
            *field = tmp_val;
        }
    }

    return res;
}

/* Filters an event according to the filter specified by mon and then adds it to
 * mons notification queue */
static UA_StatusCode
UA_MonitoredItem_addEvent(UA_MonitoredItem *mon, UA_FilterEvalContext *ctx) {
    /* Evaluate the where clause */
    UA_StatusCode res = evaluateWhereClause(ctx);
    if(res != UA_STATUSCODE_GOOD) {
        if(res == UA_STATUSCODE_BADNOMATCH)
            res = UA_STATUSCODE_GOOD;
        return res;
    }

    /* Allocate memory for the notification */
    UA_Notification *n = UA_Notification_new();
    if(!n)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Evaluate the select clause to get the event fields */
    res = evaluateSelectClause(ctx, &n->data.event);
    if(res != UA_STATUSCODE_GOOD) {
        UA_EventFieldList_clear(&n->data.event);
        UA_free(n);
        return res;
    }

    /* Finalize and enqueue the notification */
    n->data.event.clientHandle = mon->parameters.clientHandle;
    n->mon = mon;
    UA_Notification_enqueueAndTrigger(ctx->server, n);
    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_HISTORIZING
static void
setHistoricalEvent(UA_Server *server, const UA_NodeId *emitNode,
                   const UA_EventDescription *ed) {
    UA_Variant historicalEventFilterValue;
    UA_Variant_init(&historicalEventFilterValue);

    /* A HistoricalEventNode that has event history available will provide this property */
    UA_StatusCode retval =
        readObjectProperty(server, *emitNode,
                           UA_QUALIFIEDNAME(0, "HistoricalEventFilter"),
                           &historicalEventFilterValue);
    if(retval != UA_STATUSCODE_GOOD) {
        if(retval != UA_STATUSCODE_BADNOMATCH)
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Cannot read the HistoricalEventFilter property of a "
                           "listening node. StatusCode %s",
                           UA_StatusCode_name(retval));
        return;
    }

    /* If found then check if HistoricalEventFilter property has a valid value */
    if(!UA_Variant_hasScalarType(&historicalEventFilterValue,
                                 &UA_TYPES[UA_TYPES_EVENTFILTER])) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "HistoricalEventFilter property of a listening node "
                       "does not have a valid value");
        UA_Variant_clear(&historicalEventFilterValue);
        return;
    }
    UA_EventFilter *ef = (UA_EventFilter*)historicalEventFilterValue.data;

    UA_FilterEvalContext ctx;
    UA_FilterEvalContext_init(&ctx);
    ctx.server = server;
    ctx.session = &server->adminSession;
    ctx.filter = *ef;
    ctx.ed = *ed;

    /* Evaluate the where clause */
    UA_StatusCode res = evaluateWhereClause(&ctx);
    if(res != UA_STATUSCODE_GOOD) {
        UA_FilterEvalContext_reset(&ctx);
        UA_Variant_clear(&historicalEventFilterValue);
        return;
    }

    /* Get the event fields for the select clause */
    UA_EventFieldList efl;
    UA_EventFieldList_init(&efl);
    res = evaluateSelectClause(&ctx, &efl);

    /* Call the history database backend */
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
        server->config.historyDatabase.
            setEvent(server, server->config.historyDatabase.context,
                     &ed->sourceNode, emitNode, ef, &efl);
    }

    UA_FilterEvalContext_reset(&ctx);
    UA_Variant_clear(&historicalEventFilterValue);
    UA_EventFieldList_clear(&efl);
}
#endif

#define EMIT_REFS_ROOT_COUNT 4
static const UA_NodeId emitReferencesRoots[EMIT_REFS_ROOT_COUNT] =
    {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}},
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}},
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASEVENTSOURCE}},
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASNOTIFIER}}};

UA_StatusCode
createEvent(UA_Server *server, const UA_EventDescription *ed,
            UA_ByteString *outEventId) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* MonitoredItem can only be filtered if the Subscription is defined.
     * Subscription can only be filtered if a Session is defined. */
    if((ed->subscriptionId && !ed->sessionId) ||
       (ed->monitoredItemId && !ed->subscriptionId)) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Event shall be created with a filter on Subscription (or MonitoredItem), "
                       "but no Session (or Subscription) is defined");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Events: An event of severity %u is emitted by node %N",
                 ed->severity, ed->sourceNode);

#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
    UA_Boolean isCallerAC = false;
    if(isConditionOrBranch(server, &ed->eventType, &ed->sourceNode, &isCallerAC) &&
       !isCallerAC) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Condition Events: Please use A&C API to trigger Condition Events 0x%08X",
                       UA_STATUSCODE_BADINVALIDARGUMENT);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */

    /* The user must ensure that only nodes from the Objects folder (and Views)
     * emit events. The following commented code could enforce this, but is
     * computationally expensive. */

    /* static const UA_NodeId objectsFolderId = */
    /*     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_OBJECTSFOLDER}}; */
    /* static const UA_NodeId isInFolderReferences[2] = */
    /*     {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}}, */
    /*      {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}}; */
    /* UA_ReferenceTypeSet refTypes; */
    /* UA_ReferenceTypeSet_init(&refTypes); */
    /* for(int i = 0; i < 2; ++i) { */
    /*     UA_ReferenceTypeSet tmpRefTypes; */
    /*     res = referenceTypeIndices(server, &isInFolderReferences[i], &tmpRefTypes, true); */
    /*     if(res != UA_STATUSCODE_GOOD) { */
    /*         UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER, */
    /*                        "Events: Could not create the list of references and their subtypes " */
    /*                        "with StatusCode %s", UA_StatusCode_name(res)); */
    /*     } */
    /*     refTypes = UA_ReferenceTypeSet_union(refTypes, tmpRefTypes); */
    /* } */
    /* if(!isNodeInTree(server, &origin, &objectsFolderId, &refTypes)) { */
    /*     UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND, */
    /*                  "Node for event must be in ObjectsFolder!"); */
    /*     return UA_STATUSCODE_BADINVALIDARGUMENT; */
    /* } */

    /* Get all ReferenceTypes over which the events propagate */
    UA_ReferenceTypeSet emitRefTypes;
    UA_ReferenceTypeSet_init(&emitRefTypes);
    for(size_t i = 0; i < EMIT_REFS_ROOT_COUNT; i++) {
        UA_ReferenceTypeSet tmpRefTypes;
        res = referenceTypeIndices(server, &emitReferencesRoots[i], &tmpRefTypes, true);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Events: Could not create the list of references for event "
                           "propagation with StatusCode %s", UA_StatusCode_name(res));
            return res;
        }
        emitRefTypes = UA_ReferenceTypeSet_union(emitRefTypes, tmpRefTypes);
    }

    /* Get the list of nodes in the hierarchy that emits the event. Add the
     * server node to the list of nodes from which the event is emitted. The
     * server node emits all events.
     *
     * Part 3, 7.17: In particular, the root notifier of a Server, the Server
     * Object defined in Part 5, is always capable of supplying all Events from
     * a Server and as such has implied HasEventSource References to every event
     * source in a Server. */
    UA_NodeId emitStartNodes[2];
    emitStartNodes[0] = ed->sourceNode;
    emitStartNodes[1] = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);

    UA_ExpandedNodeId *emitNodes = NULL;
    size_t emitNodesSize = 0;
    res = browseRecursive(server, 2, emitStartNodes, UA_BROWSEDIRECTION_INVERSE,
                          &emitRefTypes, UA_NODECLASS_UNSPECIFIED, true,
                          &emitNodesSize, &emitNodes);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Events: Could not create the list of nodes listening on the "
                       "event with StatusCode %s", UA_StatusCode_name(res));
        return res;
    }

    /* Set up the eval context. */
    UA_FilterEvalContext ctx;
    UA_FilterEvalContext_init(&ctx);
    ctx.server = server;
    ctx.ed = *ed;
    /* ctx.session is set below for each MonitoredItem */
    /* ctx.filter is set below for each MonitoredItem */

    /* Create / resolve the EventId and copy into outEventId */
    if(outEventId) {
        ctx.session = &server->adminSession;
        res = cacheEventId(&ctx);
        if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
            res = UA_ByteString_copy(&ctx.eventId, outEventId);
        UA_FilterEvalContext_reset(&ctx);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Loop over all nodes that emit this event instance */
    for(size_t i = 0; i < emitNodesSize; i++) {
        /* We can only emit on local nodes */
        if(!UA_ExpandedNodeId_isLocal(&emitNodes[i]))
            continue;

        /* Get the node */
        const UA_Node *node = UA_NODESTORE_GET(server, &emitNodes[i].nodeId);
        if(!node)
            continue;

        /* Only consider objects */
        if(node->head.nodeClass != UA_NODECLASS_OBJECT) {
            UA_NODESTORE_RELEASE(server, node);
            continue;
        }

        /* Iterate over all MonitoredItems registered in the node  */
        for(UA_MonitoredItem *mon = node->head.monitoredItems;
            mon != NULL; mon = mon->sampling.nodeListNext) {
            /* Is this an Event-MonitoredItem? */
            if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER)
                continue;

            /* Filter on the Session. If a subscription is not attached to a
             * session, then this filter never matches. */
            UA_Subscription *sub = mon->subscription;
            if(ed->sessionId && (!sub->session || !UA_NodeId_equal(ed->sessionId, &sub->session->sessionId)))
                continue;

            /* Filter on the SubscriptionId */
            if(ed->subscriptionId && *ed->subscriptionId != sub->subscriptionId)
                continue;

            /* Filter on the MonitoredItemId */
            if(ed->monitoredItemId && *ed->monitoredItemId != mon->monitoredItemId)
                continue;

            /* Get the EventFilter from the MonitoredItem */
            if(!UA_ExtensionObject_hasDecodedType(&mon->parameters.filter,
                                                  &UA_TYPES[UA_TYPES_EVENTFILTER])) {
                UA_LOG_ERROR_SUBSCRIPTION(server->config.logging, mon->subscription,
                                          "MonitoredItem %" PRIi32 " | "
                                          "The filter must be an EventFilter", mon->monitoredItemId);
                continue;
            }
            ctx.filter = *(UA_EventFilter*)mon->parameters.filter.content.decoded.data;

            /* Select the session used to resolve SimpleAttributeOperands. If
             * the subscription is not bound to a session, use the AdminSession.
             * TODO: Preserve the access rights of the last connected session? */
            ctx.session = (sub->session) ? sub->session : &server->adminSession;

            /* Evaluate the where-clause and create a notification */
            res = UA_MonitoredItem_addEvent(mon, &ctx);
            UA_FilterEvalContext_reset(&ctx);
            if(res != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                               "Events: Could not add the event to a listening "
                               "node with StatusCode %s", UA_StatusCode_name(res));
                res = UA_STATUSCODE_GOOD; /* Only log problems with individual emit nodes */
            }
        }

        UA_NODESTORE_RELEASE(server, node);

        /* Add event entry in the historical database */
#ifdef UA_ENABLE_HISTORIZING
        if(server->config.historyDatabase.setEvent)
            setHistoricalEvent(server, &emitNodes[i].nodeId, ed);
#endif
    }

    /* Clean up and return */
    if(outEventId && res != UA_STATUSCODE_GOOD)
        UA_ByteString_clear(outEventId);
    UA_Array_delete(emitNodes, emitNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    return res;
}

UA_StatusCode
UA_Server_createEvent(UA_Server *server, const UA_NodeId sourceNode,
                      const UA_NodeId eventType, UA_UInt16 severity,
                      const UA_LocalizedText message,
                      const UA_KeyValueMap *eventFields,
                      const UA_NodeId *eventInstance,
                      UA_ByteString *outEventId) {
    UA_EventDescription ed = {0};
    ed.sourceNode = sourceNode;
    ed.eventType = eventType;
    ed.severity = severity;
    ed.message = message;
    ed.eventFields = eventFields;
    ed.eventInstance = eventInstance;

    lockServer(server);
    UA_StatusCode res = createEvent(server, &ed, outEventId);
    unlockServer(server);
    return res;
}

UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Server_createEventEx(UA_Server *server,
                        const UA_EventDescription *ed,
                        UA_ByteString *outEventId) {
    lockServer(server);
    UA_StatusCode res = createEvent(server, ed, outEventId);
    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */

/**** amalgamated original file "/src/server/ua_subscription_alarms_conditions.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Sameer AL-Qadasi)
 *    Copyright 2020-2022 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS

typedef enum {
    UA_INACTIVE = 0,
    UA_ACTIVE,
    UA_ACTIVE_HIGHHIGH,
    UA_ACTIVE_HIGH,
    UA_ACTIVE_LOW,
    UA_ACTIVE_LOWLOW
} UA_ActiveState;

/* In Alarms and Conditions first implementation, conditionBranchId is always
 * equal to NULL NodeId (UA_NODEID_NULL). That ConditionBranch represents the
 * current state Condition. The current state is determined by the last Event
 * triggered (lastEventId). See Part 9, 5.5.2, BranchId. */
typedef struct UA_ConditionBranch {
    LIST_ENTRY(UA_ConditionBranch) listEntry;
    UA_NodeId conditionBranchId;
    UA_ByteString lastEventId;
    UA_Boolean isCallerAC;
} UA_ConditionBranch;

/* In Alarms and Conditions first implementation, A Condition
 * have only one ConditionBranch entry. */
typedef struct UA_Condition {
    LIST_ENTRY(UA_Condition) listEntry;
    LIST_HEAD(, UA_ConditionBranch) conditionBranches;
    UA_NodeId conditionId;
    UA_UInt16 lastSeverity;
    UA_DateTime lastSeveritySourceTimeStamp;

    /* These callbacks are defined by the user and must not be called with a
     * locked server mutex */
    struct {
        UA_TwoStateVariableChangeCallback enableStateCallback;
        UA_TwoStateVariableChangeCallback ackStateCallback;
        UA_Boolean ackedRemoveBranch;
        UA_TwoStateVariableChangeCallback confirmStateCallback;
        UA_Boolean confirmedRemoveBranch;
        UA_TwoStateVariableChangeCallback activeStateCallback;
    } callbacks;

    UA_ActiveState lastActiveState;
    UA_ActiveState currentActiveState;
    UA_Boolean isLimitAlarm;
} UA_Condition;

/* A ConditionSource can have multiple Conditions. */
struct UA_ConditionSource {
    LIST_ENTRY(UA_ConditionSource) listEntry;
    LIST_HEAD(, UA_Condition) conditions;
    UA_NodeId conditionSourceId;
};

#define CONDITIONOPTIONALFIELDS_SUPPORT // change array size!
#define CONDITION_SEVERITYCHANGECALLBACK_ENABLE

/* Condition Field Names */
#define CONDITION_FIELD_EVENTID                                "EventId"
#define CONDITION_FIELD_EVENTTYPE                              "EventType"
#define CONDITION_FIELD_SOURCENODE                             "SourceNode"
#define CONDITION_FIELD_SOURCENAME                             "SourceName"
#define CONDITION_FIELD_TIME                                   "Time"
#define CONDITION_FIELD_RECEIVETIME                            "ReceiveTime"
#define CONDITION_FIELD_MESSAGE                                "Message"
#define CONDITION_FIELD_SEVERITY                               "Severity"
#define CONDITION_FIELD_CONDITIONNAME                          "ConditionName"
#define CONDITION_FIELD_BRANCHID                               "BranchId"
#define CONDITION_FIELD_RETAIN                                 "Retain"
#define CONDITION_FIELD_ENABLEDSTATE                           "EnabledState"
#define CONDITION_FIELD_TWOSTATEVARIABLE_ID                    "Id"
#define CONDITION_FIELD_QUALITY                                "Quality"
#define CONDITION_FIELD_LASTSEVERITY                           "LastSeverity"
#define CONDITION_FIELD_COMMENT                                "Comment"
#define CONDITION_FIELD_CLIENTUSERID                           "ClientUserId"
#define CONDITION_FIELD_CONDITIONVARIABLE_SOURCETIMESTAMP      "SourceTimestamp"
#define CONDITION_FIELD_DISABLE                                "Disable"
#define CONDITION_FIELD_ENABLE                                 "Enable"
#define CONDITION_FIELD_ADDCOMMENT                             "AddComment"
#define CONDITION_FIELD_CONDITIONREFRESH                       "ConditionRefresh"
#define CONDITION_FIELD_ACKEDSTATE                             "AckedState"
#define CONDITION_FIELD_CONFIRMEDSTATE                         "ConfirmedState"
#define CONDITION_FIELD_ACKNOWLEDGE                            "Acknowledge"
#define CONDITION_FIELD_CONFIRM                                "Confirm"
#define CONDITION_FIELD_ACTIVESTATE                            "ActiveState"
#define CONDITION_FIELD_INPUTNODE                              "InputNode"
#define CONDITION_FIELD_SUPPRESSEDORSHELVED                    "SuppressedOrShelved"
#define CONDITION_FIELD_NORMALSTATE                            "NormalState"
#define CONDITION_FIELD_HIGHHIGHLIMIT                          "HighHighLimit"
#define CONDITION_FIELD_HIGHLIMIT                              "HighLimit"
#define CONDITION_FIELD_LOWLIMIT                               "LowLimit"
#define CONDITION_FIELD_LOWLOWLIMIT                            "LowLowLimit"
#define CONDITION_FIELD_PROPERTY_EFFECTIVEDISPLAYNAME          "EffectiveDisplayName"
#define CONDITION_FIELD_LIMITSTATE                             "LimitState"
#define CONDITION_FIELD_CURRENTSTATE                           "CurrentState"
#define CONDITION_FIELD_HIGHHIGHSTATE                          "HighHighState"
#define CONDITION_FIELD_HIGHSTATE                              "HighState"
#define CONDITION_FIELD_LOWSTATE                               "LowState"
#define CONDITION_FIELD_LOWLOWSTATE                            "LowLowState"
#define CONDITION_FIELD_DIALOGSTATE                            "DialogState"
#define CONDITION_FIELD_PROMPT                                 "Prompt"
#define CONDITION_FIELD_RESPONSEOPTIONSET                      "ResponseOptionSet"
#define CONDITION_FIELD_DEFAULTRESPONSE                        "DefaultResponse"
#define CONDITION_FIELD_LASTRESPONSE                           "LastResponse"
#define CONDITION_FIELD_OKRESPONSE                             "OkResponse"
#define CONDITION_FIELD_CANCELRESPONSE                         "CancelResponse"
#define CONDITION_FIELD_RESPOND                                "Respond"
#define CONDITION_FIELD_ENGINEERINGUNITS                       "EngineeringUnits"
#define CONDITION_FIELD_EXPIRATION_DATE                        "ExpirationDate"

#define REFRESHEVENT_SEVERITY_DEFAULT                          100
#define EXPIRATION_LIMIT_DEFAULT_VALUE                         15

#define CONDITION_FIELD_EXPIRATION_LIMIT                       "ExpirationLimit"

#define LOCALE                                                 "en"
#define LOCALE_NULL                                             ""
#define TEXT_NULL                                               ""
#define ENABLED_TEXT                                           "Enabled"
#define DISABLED_TEXT                                          "Disabled"
#define ENABLED_MESSAGE                                        "The alarm was enabled"
#define DISABLED_MESSAGE                                       "The alarm was disabled"
#define COMMENT_MESSAGE                                        "A comment was added"
#define SEVERITY_INCREASED_MESSAGE                             "The alarm severity has increased"
#define SEVERITY_DECREASED_MESSAGE                             "The alarm severity has decreased"
#define ACKED_TEXT                                             "Acknowledged"
#define UNACKED_TEXT                                           "Unacknowledged"
#define CONFIRMED_TEXT                                         "Confirmed"
#define UNCONFIRMED_TEXT                                       "Unconfirmed"
#define ACKED_MESSAGE                                          "The alarm was acknowledged"
#define CONFIRMED_MESSAGE                                      "The alarm was confirmed"
#define ACTIVE_TEXT                                            "Active"
#define ACTIVE_HIGHHIGH_TEXT                                   "HighHigh active"
#define ACTIVE_HIGH_TEXT                                       "High active"
#define ACTIVE_LOW_TEXT                                        "Low active"
#define ACTIVE_LOWLOW_TEXT                                     "LowLow active"
#define INACTIVE_TEXT                                          "Inactive"

#define STATIC_QN(name) {0, UA_STRING_STATIC(name)}
static const UA_QualifiedName fieldEnabledStateQN = STATIC_QN(CONDITION_FIELD_ENABLEDSTATE);
static const UA_QualifiedName fieldRetainQN = STATIC_QN(CONDITION_FIELD_RETAIN);
static const UA_QualifiedName twoStateVariableIdQN = STATIC_QN(CONDITION_FIELD_TWOSTATEVARIABLE_ID);
static const UA_QualifiedName fieldMessageQN = STATIC_QN(CONDITION_FIELD_MESSAGE);
static const UA_QualifiedName fieldAckedStateQN = STATIC_QN(CONDITION_FIELD_ACKEDSTATE);
static const UA_QualifiedName fieldConfirmedStateQN = STATIC_QN(CONDITION_FIELD_CONFIRMEDSTATE);
static const UA_QualifiedName fieldActiveStateQN = STATIC_QN(CONDITION_FIELD_ACTIVESTATE);
static const UA_QualifiedName fieldTimeQN = STATIC_QN(CONDITION_FIELD_TIME);
static const UA_QualifiedName fieldSourceQN = STATIC_QN(CONDITION_FIELD_SOURCENODE);
static const UA_QualifiedName fieldLimitStateQN = STATIC_QN(CONDITION_FIELD_LIMITSTATE);
static const UA_QualifiedName fieldLowLimitQN = STATIC_QN(CONDITION_FIELD_LOWLIMIT);
static const UA_QualifiedName fieldLowLowLimitQN = STATIC_QN(CONDITION_FIELD_LOWLOWLIMIT);
static const UA_QualifiedName fieldHighLimitQN = STATIC_QN(CONDITION_FIELD_HIGHLIMIT);
static const UA_QualifiedName fieldHighHighLimitQN = STATIC_QN(CONDITION_FIELD_HIGHHIGHLIMIT);
static const UA_QualifiedName fieldEngineeringUnitsQN = STATIC_QN(CONDITION_FIELD_ENGINEERINGUNITS);
static const UA_QualifiedName fieldExpirationDateQN = STATIC_QN(CONDITION_FIELD_EXPIRATION_DATE);

static const UA_QualifiedName fieldExpirationLimitQN = STATIC_QN(CONDITION_FIELD_EXPIRATION_LIMIT);

#define CONDITION_ASSERT_RETURN_RETVAL(retval, logMessage, deleteFunction)                \
    {                                                                                     \
        if(retval != UA_STATUSCODE_GOOD) {                                                \
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,                  \
                         logMessage". StatusCode %s", UA_StatusCode_name(retval));        \
            deleteFunction                                                                \
            return retval;                                                                \
        }                                                                                 \
    }

#define CONDITION_ASSERT_RETURN_VOID(retval, logMessage, deleteFunction)                  \
    {                                                                                     \
        if(retval != UA_STATUSCODE_GOOD) {                                                \
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,                  \
                         logMessage". StatusCode %s", UA_StatusCode_name(retval));        \
            deleteFunction                                                                \
            return;                                                                       \
        }                                                                                 \
    }

static UA_StatusCode
setConditionField(UA_Server *server, const UA_NodeId condition,
                  const UA_Variant* value, const UA_QualifiedName fieldName);

static UA_StatusCode
setConditionVariableFieldProperty(UA_Server *server, const UA_NodeId condition,
                                  const UA_Variant* value,
                                  const UA_QualifiedName variableFieldName,
                                  const UA_QualifiedName variablePropertyName);

static UA_StatusCode
triggerConditionEvent(UA_Server *server, const UA_NodeId condition,
                      const UA_NodeId conditionSource, UA_ByteString *outEventId);

static UA_StatusCode
addConditionOptionalField(UA_Server *server, const UA_NodeId condition,
                          const UA_NodeId conditionType, const UA_QualifiedName fieldName,
                          UA_NodeId *outOptionalNode);

static UA_ConditionSource *
getConditionSource(UA_Server *server, const UA_NodeId *sourceId) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_ConditionSource *cs;
    LIST_FOREACH(cs, &server->conditionSources, listEntry) {
        if(UA_NodeId_equal(&cs->conditionSourceId, sourceId))
            return cs;
    }
    return NULL;
}

static UA_Condition *
getCondition(UA_Server *server, const UA_NodeId *sourceId,
             const UA_NodeId *conditionId) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_ConditionSource *cs = getConditionSource(server, sourceId);
    if(!cs)
        return NULL;

    UA_Condition *c;
    LIST_FOREACH(c, &cs->conditions, listEntry) {
        if(UA_NodeId_equal(&c->conditionId, conditionId))
            return c;
    }
    return NULL;
}

/* Function used to set a user specific callback to TwoStateVariable Fields of a
 * condition. The callbacks will be called before triggering the events when
 * transition to true State of EnabledState/Id, AckedState/Id, ConfirmedState/Id
 * and ActiveState/Id occurs.
 * @param removeBranch is not used for the first implementation */
UA_StatusCode
UA_Server_setConditionTwoStateVariableCallback(UA_Server *server, const UA_NodeId condition,
                                               const UA_NodeId conditionSource, UA_Boolean removeBranch,
                                               UA_TwoStateVariableChangeCallback callback,
                                               UA_TwoStateVariableCallbackType callbackType) {
    lockServer(server);

    /* Get Condition */
    UA_Condition *c = getCondition(server, &conditionSource, &condition);
    if(!c) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Set the callback */
    switch(callbackType) {
    case UA_ENTERING_ENABLEDSTATE:
        c->callbacks.enableStateCallback = callback;
        break;
    case UA_ENTERING_ACKEDSTATE:
        c->callbacks.ackStateCallback = callback;
        c->callbacks.ackedRemoveBranch = removeBranch;
        break;
    case UA_ENTERING_CONFIRMEDSTATE:
        c->callbacks.confirmStateCallback = callback;
        c->callbacks.confirmedRemoveBranch = removeBranch;
        break;
    case UA_ENTERING_ACTIVESTATE:
        c->callbacks.activeStateCallback = callback;
        break;
    default:
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
getConditionTwoStateVariableCallback(UA_Server *server, const UA_NodeId *branch,
                                     UA_Condition *condition, UA_Boolean *removeBranch,
                                     UA_TwoStateVariableCallbackType callbackType) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* That callbacks are defined in the userland. Release the server lock before. */
    unlockServer(server);

    /* TODO log warning when the callback wasn't set */
    switch(callbackType) {
    case UA_ENTERING_ENABLEDSTATE:
        if(condition->callbacks.enableStateCallback)
            res = condition->callbacks.enableStateCallback(server, branch);
        break;

    case UA_ENTERING_ACKEDSTATE:
        if(condition->callbacks.ackStateCallback) {
            *removeBranch = condition->callbacks.ackedRemoveBranch;
            res = condition->callbacks.ackStateCallback(server, branch);
        }
        break;

    case UA_ENTERING_CONFIRMEDSTATE:
        if(condition->callbacks.confirmStateCallback) {
            *removeBranch = condition->callbacks.confirmedRemoveBranch;
            res = condition->callbacks.confirmStateCallback(server, branch);
        }
        break;

    case UA_ENTERING_ACTIVESTATE:
        if(condition->callbacks.activeStateCallback)
            res = condition->callbacks.activeStateCallback(server, branch);
        break;

    default:
        res = UA_STATUSCODE_BADNOTFOUND;
        break;
    }
    lockServer(server);

    return res;
}

static UA_StatusCode
callConditionTwoStateVariableCallback(UA_Server *server, const UA_NodeId *condition,
                                      const UA_NodeId *conditionSource, UA_Boolean *removeBranch,
                                      UA_TwoStateVariableCallbackType callbackType) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_ConditionSource *source = getConditionSource(server, conditionSource);
    if(!source)
        return UA_STATUSCODE_BADNOTFOUND;

    UA_Condition *cond;
    LIST_FOREACH(cond, &source->conditions, listEntry) {
        if(UA_NodeId_equal(&cond->conditionId, condition)) {
            return getConditionTwoStateVariableCallback(server, condition, cond,
                                                        removeBranch, callbackType);
        }
        UA_ConditionBranch *branch;
        LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
            if(!UA_NodeId_equal(&branch->conditionBranchId, condition))
                continue;
            return getConditionTwoStateVariableCallback(server, &branch->conditionBranchId,
                                                        cond, removeBranch, callbackType);
        }
    }
    return UA_STATUSCODE_BADNOTFOUND;
}

static UA_StatusCode
UA_Server_callConditionTwoStateVariableCallback(UA_Server *server, const UA_NodeId *condition,
                                                const UA_NodeId *conditionSource,
                                                UA_Boolean *removeBranch,
                                                UA_TwoStateVariableCallbackType callbackType) {
    lockServer(server);
    UA_StatusCode res = callConditionTwoStateVariableCallback(server, condition, conditionSource,
                                                              removeBranch, callbackType);
    unlockServer(server);
    return res;
}

static void *
copyFieldParent(void *context, UA_ReferenceTarget *t) {
    UA_NodeId *parent = (UA_NodeId*)context;
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;
    UA_NodeId tmpNodeId = UA_NodePointer_toNodeId(t->targetId);
    UA_StatusCode res = UA_NodeId_copy(&tmpNodeId, parent);
    return (res == UA_STATUSCODE_GOOD) ? (void*)0x1 : NULL;
}

/* Gets the parent NodeId of a Field (e.g. Severity) or Field Property (e.g.
 * EnabledState/Id) */
static UA_StatusCode
getFieldParentNodeId(UA_Server *server, const UA_NodeId *field, UA_NodeId *parent) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    *parent = UA_NODEID_NULL;
    const UA_Node *fieldNode = UA_NODESTORE_GET(server, field);
    if(!fieldNode)
        return UA_STATUSCODE_BADNOTFOUND;
    for(size_t i = 0; i < fieldNode->head.referencesSize; i++) {
        UA_NodeReferenceKind *rk = &fieldNode->head.references[i];
        if(rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASPROPERTY &&
           rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASCOMPONENT)
            continue;
        if(!rk->isInverse)
            continue;
        /* Take the first hierarchical inverse reference */
        void *success = UA_NodeReferenceKind_iterate(rk, copyFieldParent, parent);
        if(success) {
            UA_NODESTORE_RELEASE(server, (const UA_Node *)fieldNode);
            return UA_STATUSCODE_GOOD;
        }
    }
    UA_NODESTORE_RELEASE(server, (const UA_Node *)fieldNode);
    return UA_STATUSCODE_BADNOTFOUND;
}

static UA_StatusCode
UA_Server_getFieldParentNodeId(UA_Server *server, const UA_NodeId *field, UA_NodeId *parent) {
    lockServer(server);
    UA_StatusCode res = getFieldParentNodeId(server, field, parent);
    unlockServer(server);
    return res;
}

/* Gets the NodeId of a Field (e.g. Severity) */
static UA_StatusCode
getConditionFieldNodeId(UA_Server *server, const UA_NodeId *conditionNodeId,
                        const UA_QualifiedName* fieldName, UA_NodeId *outFieldNodeId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_BrowsePathResult bpr =
        browseSimplifiedBrowsePath(server, *conditionNodeId, 1, fieldName);
    if(bpr.statusCode != UA_STATUSCODE_GOOD)
        return bpr.statusCode;
    UA_StatusCode retval = UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, outFieldNodeId);
    UA_BrowsePathResult_clear(&bpr);
    return retval;
}

/* Gets the NodeId of a Field Property (e.g. EnabledState/Id) */
static UA_StatusCode
getConditionFieldPropertyNodeId(UA_Server *server, const UA_NodeId *originCondition,
                                const UA_QualifiedName* variableFieldName,
                                const UA_QualifiedName* variablePropertyName,
                                UA_NodeId *outFieldPropertyNodeId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* 1) Find Variable Field of the Condition */
    UA_BrowsePathResult bprConditionVariableField =
        browseSimplifiedBrowsePath(server, *originCondition, 1, variableFieldName);
    if(bprConditionVariableField.statusCode != UA_STATUSCODE_GOOD)
        return bprConditionVariableField.statusCode;

    /* 2) Find Property of the Variable Field of the Condition */
    UA_BrowsePathResult bprVariableFieldProperty =
        browseSimplifiedBrowsePath(server, bprConditionVariableField.targets->targetId.nodeId,
                                   1, variablePropertyName);
    if(bprVariableFieldProperty.statusCode != UA_STATUSCODE_GOOD) {
        UA_BrowsePathResult_clear(&bprConditionVariableField);
        return bprVariableFieldProperty.statusCode;
    }

    *outFieldPropertyNodeId = bprVariableFieldProperty.targets[0].targetId.nodeId;
    UA_NodeId_init(&bprVariableFieldProperty.targets[0].targetId.nodeId);
    UA_BrowsePathResult_clear(&bprConditionVariableField);
    UA_BrowsePathResult_clear(&bprVariableFieldProperty);
    return UA_STATUSCODE_GOOD;
}

/* Gets NodeId value of a Field which has NodeId as DataType (e.g. EventType) */
static UA_StatusCode
getNodeIdValueOfConditionField(UA_Server *server, const UA_NodeId *condition,
                               UA_QualifiedName fieldName, UA_NodeId *outNodeId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    *outNodeId = UA_NODEID_NULL;
    UA_NodeId nodeIdValue;
    UA_StatusCode retval = getConditionFieldNodeId(server, condition, &fieldName, &nodeIdValue);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Field not found",);

    /* Read the Value of SourceNode Property Node (the Value is a NodeId) */
    UA_Variant tOutVariant;
    retval = readWithReadValue(server, &nodeIdValue, UA_ATTRIBUTEID_VALUE, &tOutVariant);
    if(retval != UA_STATUSCODE_GOOD ||
       !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_NODEID])) {
        UA_NodeId_clear(&nodeIdValue);
        UA_Variant_clear(&tOutVariant);
        return retval;
    }

    *outNodeId = *(UA_NodeId*)tOutVariant.data;
    UA_NodeId_init((UA_NodeId*)tOutVariant.data);
    UA_NodeId_clear(&nodeIdValue);
    UA_Variant_clear(&tOutVariant);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Server_getNodeIdValueOfConditionField(UA_Server *server, const UA_NodeId *condition,
                                         UA_QualifiedName fieldName, UA_NodeId *outNodeId) {
    lockServer(server);
    UA_StatusCode res = getNodeIdValueOfConditionField(server, condition, fieldName, outNodeId);
    unlockServer(server);
    return res;
}

/* Gets the NodeId of a condition branch. In case of main branch (BranchId ==
 * UA_NODEID_NULL), ConditionId will be returned. */
static UA_StatusCode
UA_Server_getConditionBranchNodeId(UA_Server *server, const UA_ByteString *eventId,
                         UA_NodeId *outConditionBranchNodeId) {
    lockServer(server);

    *outConditionBranchNodeId = UA_NODEID_NULL;
    /* The function checks the BranchId based on the event Id, if BranchId ==
       NULL -> outConditionId = ConditionId */
    /* Get ConditionSource Entry */
    UA_StatusCode res = UA_STATUSCODE_BADEVENTIDUNKNOWN;
    UA_ConditionSource *source;
    LIST_FOREACH(source, &server->conditionSources, listEntry) {
        /* Get Condition Entry */
        UA_Condition *cond;
        LIST_FOREACH(cond, &source->conditions, listEntry) {
            /* Get Branch Entry*/
            UA_ConditionBranch *branch;
            LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
                if(!UA_ByteString_equal(&branch->lastEventId, eventId))
                    continue;
                if(UA_NodeId_isNull(&branch->conditionBranchId)) {
                    res = UA_NodeId_copy(&cond->conditionId, outConditionBranchNodeId);
                    unlockServer(server);
                    return res;
                } else {
                    res = UA_NodeId_copy(&branch->conditionBranchId, outConditionBranchNodeId);
                    unlockServer(server);
                    return res;
                }
                goto out;
            }
        }
    }

 out:
    unlockServer(server);
    return res;
}

static UA_StatusCode
UA_Server_getConditionLastSeverity(UA_Server *server, const UA_NodeId *conditionSource,
                         const UA_NodeId *conditionId, UA_UInt16 *outLastSeverity,
                         UA_DateTime *outLastSeveritySourceTimeStamp) {
    lockServer(server);
    UA_Condition *cond = getCondition(server, conditionSource, conditionId);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    *outLastSeverity = cond->lastSeverity;
    *outLastSeveritySourceTimeStamp = cond->lastSeveritySourceTimeStamp;
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Server_updateConditionLastSeverity(UA_Server *server, const UA_NodeId *conditionSource,
                                      const UA_NodeId *conditionId, UA_UInt16 lastSeverity,
                                      UA_DateTime lastSeveritySourceTimeStamp) {
    lockServer(server);
    UA_Condition *cond = getCondition(server, conditionSource, conditionId);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    cond->lastSeverity = lastSeverity;
    cond->lastSeveritySourceTimeStamp =  lastSeveritySourceTimeStamp;
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Server_getConditionActiveState(UA_Server *server, const UA_NodeId *conditionSource,
                                  const UA_NodeId *conditionId, UA_ActiveState *outLastActiveState,
                                  UA_ActiveState *outCurrentActiveState, UA_Boolean *outIsLimitAlarm) {
    lockServer(server);
    UA_Condition *cond = getCondition(server, conditionSource, conditionId);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    *outLastActiveState = cond->lastActiveState;
    *outCurrentActiveState = cond->currentActiveState;
    *outIsLimitAlarm = cond->isLimitAlarm;
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Server_updateConditionActiveState(UA_Server *server, const UA_NodeId *conditionSource,
                                     const UA_NodeId *conditionId, const UA_ActiveState lastActiveState,
                                     const UA_ActiveState currentActiveState, UA_Boolean isLimitAlarm) {
    lockServer(server);
    UA_Condition *cond = getCondition(server, conditionSource, conditionId);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    cond->lastActiveState = lastActiveState;
    cond->currentActiveState = currentActiveState;
    cond->isLimitAlarm = isLimitAlarm;
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
updateConditionLastEventId(UA_Server *server, const UA_NodeId *triggeredEvent,
                           const UA_NodeId *conditionSource,
                           const UA_ByteString *lastEventId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Condition *cond = getCondition(server, conditionSource, triggeredEvent);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_ConditionBranch *branch;
    LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
        if(UA_NodeId_isNull(&branch->conditionBranchId)) {
            /* update main condition branch */
            UA_ByteString_clear(&branch->lastEventId);
            return UA_ByteString_copy(lastEventId, &branch->lastEventId);
        }
    }
    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Condition Branch not implemented");
    return UA_STATUSCODE_BADNOTFOUND;
}

static void
setIsCallerAC(UA_Server *server, const UA_NodeId *condition,
              const UA_NodeId *conditionSource, UA_Boolean isCallerAC) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Condition *cond = getCondition(server, conditionSource, condition);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        return;
    }

    UA_ConditionBranch *branch;
    LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
        if(UA_NodeId_isNull(&branch->conditionBranchId)) {
            branch->isCallerAC = isCallerAC;
            return;
        }
    }
    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Condition Branch not implemented");
}

UA_Boolean
isConditionOrBranch(UA_Server *server, const UA_NodeId *condition,
                    const UA_NodeId *conditionSource, UA_Boolean *isCallerAC) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Condition *cond = getCondition(server, conditionSource, condition);
    if(!cond) {
        UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        return false;
    }

    UA_ConditionBranch *branch;
    LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
        if(UA_NodeId_isNull(&branch->conditionBranchId)) {
            *isCallerAC = branch->isCallerAC;
            return true;
        }
    }
    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Condition Branch not implemented");
    return false;
}

static UA_Boolean
isRetained(UA_Server *server, const UA_NodeId *condition) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get EnabledStateId NodeId */
    UA_NodeId retainNodeId;
    UA_StatusCode retval = getConditionFieldNodeId(server, condition, &fieldRetainQN, &retainNodeId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Retain not found. StatusCode %s", UA_StatusCode_name(retval));
        return false; //TODO maybe a better error handling?
    }

    /* Read Retain value */
    UA_Variant tOutVariant;
    retval = readWithReadValue(server, &retainNodeId, UA_ATTRIBUTEID_VALUE, &tOutVariant);
    if(retval != UA_STATUSCODE_GOOD ||
       !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_BOOLEAN])) {
          UA_NodeId_clear(&retainNodeId);
          return false;
    }

    if(*(UA_Boolean *)tOutVariant.data == true) {
        UA_NodeId_clear(&retainNodeId);
        UA_Variant_clear(&tOutVariant);
        return true;
    }

    UA_NodeId_clear(&retainNodeId);
    UA_Variant_clear(&tOutVariant);
    return false;
}

static UA_Boolean
UA_Server_isRetained(UA_Server *server, const UA_NodeId *condition) {
    lockServer(server);
    UA_Boolean res = isRetained(server, condition);
    unlockServer(server);
    return res;
}

static UA_Boolean
isTwoStateVariableInTrueState(UA_Server *server, const UA_NodeId *condition,
                              const UA_QualifiedName *twoStateVariable) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get TwoStateVariableId NodeId */
    UA_NodeId twoStateVariableIdNodeId;
    UA_StatusCode retval = getConditionFieldPropertyNodeId(server, condition, twoStateVariable,
                                                           &twoStateVariableIdQN,
                                                           &twoStateVariableIdNodeId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "TwoStateVariable/Id not found. StatusCode %s", UA_StatusCode_name(retval));
        return false; //TODO maybe a better error handling?
    }

    /* Read Id value */
    UA_Variant tOutVariant;
    retval = readWithReadValue(server, &twoStateVariableIdNodeId, UA_ATTRIBUTEID_VALUE, &tOutVariant);
    if(retval != UA_STATUSCODE_GOOD ||
       !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_BOOLEAN])) {
        UA_NodeId_clear(&twoStateVariableIdNodeId);
        return false;
    }

    UA_NodeId_clear(&twoStateVariableIdNodeId);

    if(*(UA_Boolean *)tOutVariant.data == true) {
      UA_Variant_clear(&tOutVariant);
      return true;
    }

    UA_Variant_clear(&tOutVariant);
    return false;
}

static UA_Boolean
UA_Server_isTwoStateVariableInTrueState(UA_Server *server, const UA_NodeId *condition,
                                        const UA_QualifiedName *twoStateVariable) {
    lockServer(server);
    UA_Boolean res = isTwoStateVariableInTrueState(server, condition, twoStateVariable);
    unlockServer(server);
    return res;
}

static UA_StatusCode
enteringDisabledState(UA_Server *server, const UA_NodeId *conditionId,
                      const UA_NodeId *conditionSource) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Condition *cond = getCondition(server, conditionSource, conditionId);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Get Branch Entry*/
    UA_ConditionBranch *branch;
    LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
        UA_NodeId triggeredNode;
        if(UA_NodeId_isNull(&branch->conditionBranchId))
            //disable main Condition Branch (BranchId == NULL)
            triggeredNode = cond->conditionId;
        else //disable all branches
            triggeredNode = branch->conditionBranchId;

        UA_LocalizedText message = UA_LOCALIZEDTEXT(LOCALE, DISABLED_MESSAGE);
        UA_LocalizedText enableText = UA_LOCALIZEDTEXT(LOCALE, DISABLED_TEXT);
        UA_Variant value;
        UA_Variant_setScalar(&value, &message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        UA_StatusCode retval = setConditionField(server, triggeredNode, &value, fieldMessageQN);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition Message failed",);

        UA_Variant_setScalar(&value, &enableText, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = setConditionField(server, triggeredNode, &value, fieldEnabledStateQN);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition EnabledState text failed",);

        UA_Boolean retain = false;
        UA_Variant_setScalar(&value, &retain, &UA_TYPES[UA_TYPES_BOOLEAN]);
        retval = setConditionField(server, triggeredNode, &value, fieldRetainQN);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition Retain failed",);

        /* Trigger event */
        UA_ByteString lastEventId = UA_BYTESTRING_NULL;
        /* Trigger the event for Condition or its Branch */
        setIsCallerAC(server, &triggeredNode, conditionSource, true);
        /* Condition Nodes should not be deleted after triggering the event */
        UA_EventDescription ed = {0};
        ed.eventInstance = &triggeredNode;
        ed.sourceNode = *conditionSource;
        retval = createEvent(server, &ed, &lastEventId);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Triggering condition event failed",);
        setIsCallerAC(server, &triggeredNode, conditionSource, false);

        /* Update list */
        retval = updateConditionLastEventId(server, &triggeredNode, conditionSource, &lastEventId);
        UA_ByteString_clear(&lastEventId);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "updating condition event failed",);
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Server_enteringDisabledState(UA_Server *server, const UA_NodeId *conditionId,
                                const UA_NodeId *conditionSource) {
    lockServer(server);
    UA_StatusCode res = enteringDisabledState(server, conditionId, conditionSource);
    unlockServer(server);
    return res;
}

static UA_StatusCode
enteringEnabledState(UA_Server *server,
                     const UA_NodeId *conditionId,
                     const UA_NodeId *conditionSource) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get Condition */
    UA_Condition *cond = getCondition(server, conditionSource, conditionId);
    if(!cond) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Entry not found in list!");
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Get Branch Entry*/
    UA_ConditionBranch *branch;
    LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
        UA_NodeId triggeredNode;
        UA_NodeId_init(&triggeredNode);
        if(UA_NodeId_isNull(&branch->conditionBranchId)) //enable main Condition
            triggeredNode = cond->conditionId;
        else //enable branches
            triggeredNode = branch->conditionBranchId;

        UA_LocalizedText message = UA_LOCALIZEDTEXT(LOCALE, ENABLED_MESSAGE);
        UA_LocalizedText enableText = UA_LOCALIZEDTEXT(LOCALE, ENABLED_TEXT);
        UA_Variant value;
        UA_Variant_setScalar(&value, &message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        UA_StatusCode retval = setConditionField(server, triggeredNode,
                                                           &value, fieldMessageQN);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "set Condition Message failed",);

        UA_Variant_setScalar(&value, &enableText, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = setConditionField(server, triggeredNode, &value, fieldEnabledStateQN);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "set Condition EnabledState text failed",);

        /* User callback TODO how should branches be evaluated? see p.19 (5.5.2) */
        UA_Boolean removeBranch = false;//not used
        retval = callConditionTwoStateVariableCallback(server, &triggeredNode,
                                                       conditionSource, &removeBranch,
                                                       UA_ENTERING_ENABLEDSTATE);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "calling condition callback failed",);

        /* Trigger event */
        //Condition Nodes should not be deleted after triggering the event
        retval = triggerConditionEvent(server, triggeredNode, *conditionSource, NULL);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "triggering condition event failed",);
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Server_enteringEnabledState(UA_Server *server, const UA_NodeId *conditionId,
                               const UA_NodeId *conditionSource) {
    lockServer(server);
    UA_StatusCode res = enteringEnabledState(server, conditionId, conditionSource);
    unlockServer(server);
    return res;
}

static void
afterWriteCallbackEnabledStateChange(UA_Server *server,
                                     const UA_NodeId *sessionId, void *sessionContext,
                                     const UA_NodeId *nodeId, void *nodeContext,
                                     const UA_NumericRange *range, const UA_DataValue *data) {
    /* Callback for change in EnabledState/Id property.
     * First we get the EnabledState NodeId then The Condition NodeId */
    UA_NodeId twoStateVariableNode;
    UA_StatusCode retval = UA_Server_getFieldParentNodeId(server, nodeId, &twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent TwoStateVariable found for given EnabledState/Id",);

    UA_NodeId conditionNode;
    retval = UA_Server_getFieldParentNodeId(server, &twoStateVariableNode, &conditionNode);
    UA_NodeId_clear(&twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent Condition found for given EnabledState",);

    /* Get conditionSource */
    UA_NodeId conditionSource;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &conditionNode, fieldSourceQN,
                                                      &conditionSource);
    CONDITION_ASSERT_RETURN_VOID(retval, "ConditionSource not found",
                                 UA_NodeId_clear(&conditionNode););

    /* Set disabling/enabling time */
    UA_DateTime eventTime = data->sourceTimestamp;
    /* If UA_Server_setConditionVariableFieldProperty() was used, sourceTimestamp is 0 */
    if (eventTime == 0)
        eventTime = UA_DateTime_now();
    retval = UA_Server_writeObjectProperty_scalar(server, conditionNode, fieldTimeQN,
                                                  &eventTime, &UA_TYPES[UA_TYPES_DATETIME]);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set enabling/disabling Time failed",
                                 UA_NodeId_clear(&conditionNode);
                                 UA_NodeId_clear(&conditionSource););

    if(false == (*((UA_Boolean *)data->value.data))) {
        /* Disable all branches and update list */
        retval = UA_Server_enteringDisabledState(server, &conditionNode, &conditionSource);
        UA_NodeId_clear(&conditionNode);
        CONDITION_ASSERT_RETURN_VOID(retval, "Entering disabled state failed",
                                     UA_NodeId_clear(&conditionSource););
    } else {
        /* Enable all branches and update list */
        retval = UA_Server_enteringEnabledState(server, &conditionNode, &conditionSource);
        UA_NodeId_clear(&conditionNode);
        CONDITION_ASSERT_RETURN_VOID(retval, "Entering enabled state failed",
                                     UA_NodeId_clear(&conditionSource););
    }

    UA_NodeId_clear(&conditionSource);
}

static void
afterWriteCallbackAckedStateChange(UA_Server *server,
                                   const UA_NodeId *sessionId, void *sessionContext,
                                   const UA_NodeId *nodeId, void *nodeContext,
                                   const UA_NumericRange *range, const UA_DataValue *data) {
    /* Get the AckedState NodeId then The Condition NodeId */
    UA_NodeId twoStateVariableNode;
    UA_StatusCode retval = UA_Server_getFieldParentNodeId(server, nodeId, &twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent TwoStateVariable found for given AckedState/Id",);

    UA_NodeId conditionNode;
    retval = UA_Server_getFieldParentNodeId(server, &twoStateVariableNode, &conditionNode);
    UA_NodeId_clear(&twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent Condition found for given AckedState",);

    /* Callback for change to true in AckedState/Id property.
     * First check whether the value is true (ackedState/Id == true).
     * That check makes it possible to set ackedState/Id to false, without triggering an event */
    if(*((UA_Boolean *)data->value.data) == false) {
        /* Set unacknowledging time */
        retval = UA_Server_writeObjectProperty_scalar(server, conditionNode, fieldTimeQN,
                                                      &data->sourceTimestamp,
                                                      &UA_TYPES[UA_TYPES_DATETIME]);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set deactivating Time failed",
                                     UA_NodeId_clear(&conditionNode););

        /* Set AckedState text to Unacknowledged*/
        UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, UNACKED_TEXT);
        UA_Variant value;
        UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = UA_Server_setConditionField(server, conditionNode, &value, fieldAckedStateQN);
        UA_NodeId_clear(&conditionNode);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition AckedState failed",);
        return;
    }

    /* Check if enabled and retained */
    if(!UA_Server_isTwoStateVariableInTrueState(server, &conditionNode, &fieldEnabledStateQN) ||
       !UA_Server_isRetained(server, &conditionNode)) {
        /* Set AckedState/Id to false*/
        UA_Boolean idValue = false;
        UA_Variant value;
        UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
        retval = UA_Server_setConditionVariableFieldProperty(server, conditionNode, &value,
                                                   fieldAckedStateQN, twoStateVariableIdQN);
        UA_NodeId_clear(&conditionNode);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set AckedState/Id failed",);
        return;
    }

    /* Set Message */
    UA_LocalizedText message = UA_LOCALIZEDTEXT(LOCALE, ACKED_MESSAGE);
    UA_Variant value;
    UA_Variant_setScalar(&value, &message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = UA_Server_setConditionField(server, conditionNode, &value, fieldMessageQN);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition Message failed",
                                 UA_NodeId_clear(&conditionNode););

    /* Set AckedState text */
    UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, ACKED_TEXT);
    UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = UA_Server_setConditionField(server, conditionNode, &value, fieldAckedStateQN);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition AckedState failed",
                                 UA_NodeId_clear(&conditionNode););

    /* Get conditionSource */
    UA_NodeId conditionSource;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &conditionNode, fieldSourceQN,
                                                      &conditionSource);
    CONDITION_ASSERT_RETURN_VOID(retval, "ConditionSource not found",
                                 UA_NodeId_clear(&conditionNode););

    /* User callback*/
    UA_Boolean removeBranch = false;
    retval = UA_Server_callConditionTwoStateVariableCallback(server, &conditionNode, &conditionSource,
                                                             &removeBranch, UA_ENTERING_ACKEDSTATE);
    CONDITION_ASSERT_RETURN_VOID(retval, "Calling condition callback failed",
                                 UA_NodeId_clear(&conditionNode);
                                 UA_NodeId_clear(&conditionSource););

    /* Trigger event */
    //Condition Nodes should not be deleted after triggering the event
    retval = UA_Server_triggerConditionEvent(server, conditionNode, conditionSource, NULL);
    CONDITION_ASSERT_RETURN_VOID(retval, "Triggering condition event failed",
                                 UA_NodeId_clear(&conditionNode);
                                 UA_NodeId_clear(&conditionSource););

    UA_NodeId_clear(&conditionNode);
    UA_NodeId_clear(&conditionSource);
}

#ifdef CONDITIONOPTIONALFIELDS_SUPPORT

static void
afterWriteCallbackConfirmedStateChange(UA_Server *server,
                                       const UA_NodeId *sessionId, void *sessionContext,
                                       const UA_NodeId *nodeId, void *nodeContext,
                                       const UA_NumericRange *range, const UA_DataValue *data) {
    UA_Variant value;
    UA_NodeId twoStateVariableNode;
    UA_StatusCode retval = UA_Server_getFieldParentNodeId(server, nodeId, &twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent TwoStateVariable found for given ConfirmedState/Id",);

    UA_NodeId conditionNode;
    retval = UA_Server_getFieldParentNodeId(server, &twoStateVariableNode, &conditionNode);
    UA_NodeId_clear(&twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent Condition found for given ConfirmedState",);

    /* Callback to change to true in ConfirmedState/Id property.
     * First check whether the value is true (ConfirmedState/Id == true).
     * That check makes it possible to set ConfirmedState/Id to false, without triggering an event */
    if(*((UA_Boolean *)data->value.data) == false) {
        /* Set unconfirming time */
        retval = UA_Server_writeObjectProperty_scalar(server, conditionNode, fieldTimeQN,
                                                      &data->sourceTimestamp,
                                                      &UA_TYPES[UA_TYPES_DATETIME]);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set deactivating Time failed",
                                     UA_NodeId_clear(&conditionNode););

        /* Set ConfirmedState text to (Unconfirmed)*/
        UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, UNCONFIRMED_TEXT);
        UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = UA_Server_setConditionField(server, conditionNode, &value, fieldConfirmedStateQN);
        UA_NodeId_clear(&conditionNode);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition ConfirmedState failed",);
        return;
    }

    /* Check if enabled and retained */
    if(!UA_Server_isTwoStateVariableInTrueState(server, &conditionNode, &fieldEnabledStateQN) ||
       !UA_Server_isRetained(server, &conditionNode)) {
        /* Set confirmedState/Id to false*/
        UA_Boolean idValue = false;
        UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
        retval = UA_Server_setConditionVariableFieldProperty(server, conditionNode, &value,
                                                   fieldConfirmedStateQN, twoStateVariableIdQN);
        UA_NodeId_clear(&conditionNode);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set ConfirmedState/Id failed",);
        return;
    }

    /* Set confirming time */
    retval = UA_Server_writeObjectProperty_scalar(server, conditionNode, fieldTimeQN,
                                                  &data->sourceTimestamp, &UA_TYPES[UA_TYPES_DATETIME]);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Confirming Time failed",
                                 UA_NodeId_clear(&conditionNode););

    /* Set Message */
    UA_LocalizedText message = UA_LOCALIZEDTEXT(LOCALE, CONFIRMED_MESSAGE);
    UA_Variant_setScalar(&value, &message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = UA_Server_setConditionField(server, conditionNode, &value, fieldMessageQN);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition Message failed",
                                 UA_NodeId_clear(&conditionNode););

    /* Set ConfirmedState text */
    UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, CONFIRMED_TEXT);
    UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = UA_Server_setConditionField(server, conditionNode, &value, fieldConfirmedStateQN);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition ConfirmedState failed",
                                 UA_NodeId_clear(&conditionNode););

    /* Get conditionSource */
    UA_NodeId conditionSource;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &conditionNode,
                                                      fieldSourceQN, &conditionSource);
    CONDITION_ASSERT_RETURN_VOID(retval, "ConditionSource not found",
                                 UA_NodeId_clear(&conditionNode););

    /* User callback*/
    UA_Boolean removeBranch = false;
    retval = UA_Server_callConditionTwoStateVariableCallback(server, &conditionNode,
                                                             &conditionSource, &removeBranch,
                                                             UA_ENTERING_CONFIRMEDSTATE);
    CONDITION_ASSERT_RETURN_VOID(retval, "Calling condition callback failed",
                                 UA_NodeId_clear(&conditionNode);
                                 UA_NodeId_clear(&conditionSource););

    /* Trigger event */
    //Condition Nodes should not be deleted after triggering the event
    retval = UA_Server_triggerConditionEvent(server, conditionNode, conditionSource, NULL);
    CONDITION_ASSERT_RETURN_VOID(retval, "Triggering condition event failed",
                                 UA_NodeId_clear(&conditionNode);
                                 UA_NodeId_clear(&conditionSource););
}
#endif /* CONDITIONOPTIONALFIELDS_SUPPORT */

static void
afterWriteCallbackActiveStateChange(UA_Server *server,
                                    const UA_NodeId *sessionId, void *sessionContext,
                                    const UA_NodeId *nodeId, void *nodeContext,
                                    const UA_NumericRange *range, const UA_DataValue *data) {
    UA_Variant value;
    UA_NodeId twoStateVariableNode;
    UA_StatusCode retval = UA_Server_getFieldParentNodeId(server, nodeId, &twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent TwoStateVariable found for given ActiveState/Id",);

    UA_NodeId conditionNode;
    retval = UA_Server_getFieldParentNodeId(server, &twoStateVariableNode, &conditionNode);
    UA_NodeId_clear(&twoStateVariableNode);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent Condition found for given ActiveState",);

    /* Get conditionSource */
    UA_NodeId conditionSource;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &conditionNode,
                                                      fieldSourceQN, &conditionSource);
    CONDITION_ASSERT_RETURN_VOID(retval, "ConditionSource not found",
                                 UA_NodeId_clear(&conditionNode););

    UA_ActiveState lastActiveState = UA_INACTIVE;
    UA_ActiveState currentActiveState = UA_INACTIVE;
    UA_Boolean isLimitalarm = false;

    retval = UA_Server_getConditionActiveState(server, &conditionSource, &conditionNode,
                                               &lastActiveState, &currentActiveState,
                                               &isLimitalarm);
    CONDITION_ASSERT_RETURN_VOID(retval, "ActiveState transition check failed",
                                 UA_NodeId_clear(&conditionNode);
                                 UA_NodeId_clear(&conditionSource););

    if(isLimitalarm == false) {
      if(*((UA_Boolean *)data->value.data) == true) {
        retval = UA_Server_updateConditionActiveState(server, &conditionSource, &conditionNode,
                                                      currentActiveState, UA_ACTIVE, false);
        CONDITION_ASSERT_RETURN_VOID(retval, "Updating ActiveState failed",
                                     UA_NodeId_clear(&conditionNode);
                                     UA_NodeId_clear(&conditionSource););
      } else {
        retval = UA_Server_updateConditionActiveState(server, &conditionSource, &conditionNode,
                                                      currentActiveState, UA_INACTIVE, false);
        CONDITION_ASSERT_RETURN_VOID(retval, "Updating ActiveState failed",
                                     UA_NodeId_clear(&conditionNode);
                                     UA_NodeId_clear(&conditionSource););
      }

      retval = UA_Server_getConditionActiveState(server, &conditionSource, &conditionNode,
                                                 &lastActiveState, &currentActiveState,
                                                 &isLimitalarm);
      CONDITION_ASSERT_RETURN_VOID(retval, "ActiveState transition check failed",
                                   UA_NodeId_clear(&conditionNode);
                                   UA_NodeId_clear(&conditionSource););
    }

    /* callback for change to true in ActiveState/Id property.
     * first check whether the value is true (ActiveState/Id == true).
     * That check makes it possible to set ActiveState/Id to false, without triggering an event */
    if(*((UA_Boolean *)data->value.data) == true &&
       (lastActiveState != currentActiveState)) {

        /* Check if enabled and retained */
        if(UA_Server_isTwoStateVariableInTrueState(server, &conditionNode, &fieldEnabledStateQN) &&
           UA_Server_isRetained(server, &conditionNode)) {
            /* Set activating time */
            retval = UA_Server_writeObjectProperty_scalar(server, conditionNode, fieldTimeQN,
                                                          &data->sourceTimestamp,
                                                          &UA_TYPES[UA_TYPES_DATETIME]);
            CONDITION_ASSERT_RETURN_VOID(retval, "Set activating Time failed",
                                         UA_NodeId_clear(&conditionNode);
                                         UA_NodeId_clear(&conditionSource););

            /* Set ActiveState text */
            UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, ACTIVE_TEXT);
            UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
            retval = UA_Server_setConditionField(server, conditionNode, &value, fieldActiveStateQN);
            CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition ActiveState failed",
                                         UA_NodeId_clear(&conditionNode);
                                         UA_NodeId_clear(&conditionSource););

            /* User callback*/
            UA_Boolean removeBranch = false;//not used
            retval = UA_Server_callConditionTwoStateVariableCallback(server, &conditionNode,
                                                                     &conditionSource, &removeBranch,
                                                                     UA_ENTERING_ACTIVESTATE);
            CONDITION_ASSERT_RETURN_VOID(retval, "Calling condition callback failed",
                                         UA_NodeId_clear(&conditionNode);
                                         UA_NodeId_clear(&conditionSource););

            /* Trigger event */
            //Condition Nodes should not be deleted after triggering the event
            retval = UA_Server_triggerConditionEvent(server, conditionNode, conditionSource, NULL);
            UA_NodeId_clear(&conditionNode);
            UA_NodeId_clear(&conditionSource);
            CONDITION_ASSERT_RETURN_VOID(retval, "Triggering condition event failed",);
        } else {
            /* Set ActiveState/Id to false -> don't apply changes in case of
             * disabled or not retained*/
            UA_Boolean idValue = false;
            UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
            retval = UA_Server_setConditionVariableFieldProperty(server, conditionNode, &value,
                                                                 fieldActiveStateQN,
                                                                 twoStateVariableIdQN);
            UA_NodeId_clear(&conditionSource);
            UA_NodeId_clear(&conditionNode);
            CONDITION_ASSERT_RETURN_VOID(retval, "Set ActiveState/Id failed",);
        }
        return;
    }

    if((*((UA_Boolean *)data->value.data) == false) &&
       (lastActiveState != currentActiveState)) {
        /* Set ActiveState text to (Inactive) */
        UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, INACTIVE_TEXT);
        UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = UA_Server_setConditionField(server, conditionNode, &value, fieldActiveStateQN);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition ActiveState failed",
                                     UA_NodeId_clear(&conditionNode);
                                     UA_NodeId_clear(&conditionSource););

        /* Set deactivating time */
        retval = UA_Server_writeObjectProperty_scalar(server, conditionNode, fieldTimeQN,
                                                      &data->sourceTimestamp,
                                                      &UA_TYPES[UA_TYPES_DATETIME]);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set deactivating Time failed",
                                     UA_NodeId_clear(&conditionNode);
                                     UA_NodeId_clear(&conditionSource););

        retval = UA_Server_updateConditionActiveState(server, &conditionSource, &conditionNode,
                                                      currentActiveState, UA_INACTIVE, isLimitalarm);
        UA_NodeId_clear(&conditionSource);
        UA_NodeId_clear(&conditionNode);
        CONDITION_ASSERT_RETURN_VOID(retval, "Set ActiveState failed",);
    }
}

static void
afterWriteCallbackQualityChange(UA_Server *server,
                                const UA_NodeId *sessionId, void *sessionContext,
                                const UA_NodeId *nodeId, void *nodeContext,
                                const UA_NumericRange *range, const UA_DataValue *data) {
    //TODO
}

static void
afterWriteCallbackSeverityChange(UA_Server *server,
                                 const UA_NodeId *sessionId, void *sessionContext,
                                 const UA_NodeId *nodeId, void *nodeContext,
                                 const UA_NumericRange *range, const UA_DataValue *data) {
    UA_QualifiedName fieldLastSeverity = UA_QUALIFIEDNAME(0, CONDITION_FIELD_LASTSEVERITY);
    UA_QualifiedName fieldSourceTimeStamp =
        UA_QUALIFIEDNAME(0, CONDITION_FIELD_CONDITIONVARIABLE_SOURCETIMESTAMP);
    UA_Variant value;

    UA_NodeId condition;
    UA_StatusCode retval = UA_Server_getFieldParentNodeId(server, nodeId, &condition);
    CONDITION_ASSERT_RETURN_VOID(retval, "No Parent Condition found for given Severity Field",);

    /* Get conditionSource */
    UA_NodeId conditionSource;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &condition,
                                                      fieldSourceQN, &conditionSource);
    CONDITION_ASSERT_RETURN_VOID(retval, "ConditionSource not found",
                                 UA_NodeId_clear(&condition););

    UA_UInt16 lastSeverity;
    UA_DateTime lastSeveritySourceTimeStamp;
    retval = UA_Server_getConditionLastSeverity(server, &conditionSource, &condition,
                                                &lastSeverity, &lastSeveritySourceTimeStamp);
    CONDITION_ASSERT_RETURN_VOID(retval, "Get Condition LastSeverity failed",
                                 UA_NodeId_clear(&condition);
                                 UA_NodeId_clear(&conditionSource););

    /* Set message dependent on compare result*/
    UA_LocalizedText message;
    if(lastSeverity < (*(UA_UInt16 *)data->value.data))
        message = UA_LOCALIZEDTEXT(LOCALE, SEVERITY_INCREASED_MESSAGE);
    else
        message = UA_LOCALIZEDTEXT(LOCALE, SEVERITY_DECREASED_MESSAGE);

    /* Set LastSeverity */
    UA_Variant_setScalar(&value, &lastSeverity, &UA_TYPES[UA_TYPES_UINT16]);
    retval = UA_Server_setConditionField(server, condition, &value, fieldLastSeverity);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition LAstSeverity failed",
                                 UA_NodeId_clear(&condition);
                                 UA_NodeId_clear(&conditionSource););

    /* Set SourceTimestamp */
    UA_Variant_setScalar(&value, &lastSeveritySourceTimeStamp, &UA_TYPES[UA_TYPES_DATETIME]);
    retval = UA_Server_setConditionVariableFieldProperty(server, condition, &value,
                                               fieldLastSeverity, fieldSourceTimeStamp);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set LastSeverity SourceTimestamp failed",
                                 UA_NodeId_clear(&condition);
                                 UA_NodeId_clear(&conditionSource););

    /* Update lastSeverity in list */
    lastSeverity = *(UA_UInt16 *)data->value.data;
    lastSeveritySourceTimeStamp = data->sourceTimestamp;
    retval = UA_Server_updateConditionLastSeverity(server, &conditionSource, &condition,
                                                   lastSeverity, lastSeveritySourceTimeStamp);
    CONDITION_ASSERT_RETURN_VOID(retval, "Update Condition LastSeverity failed",
                                 UA_NodeId_clear(&condition);
    UA_NodeId_clear(&conditionSource););

    /* Set Time (Time of Value Change) */
    UA_Variant_setScalar(&value, (void*)(uintptr_t)((const UA_DateTime*)&data->sourceTimestamp),
                         &UA_TYPES[UA_TYPES_DATETIME]);
    retval = UA_Server_setConditionField(server, condition, &value, fieldTimeQN);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition Time failed",
                                 UA_NodeId_clear(&condition););

    /* Set Message */
    UA_Variant_setScalar(&value, &message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = UA_Server_setConditionField(server, condition, &value, fieldMessageQN);
    CONDITION_ASSERT_RETURN_VOID(retval, "Set Condition Message failed",
                                 UA_NodeId_clear(&condition););

#ifdef CONDITION_SEVERITYCHANGECALLBACK_ENABLE
    /* Check if retained */
    if(UA_Server_isRetained(server, &condition)) {
        /* Trigger event */
        //Condition Nodes should not be deleted after triggering the event
        retval = UA_Server_triggerConditionEvent(server, condition, conditionSource, NULL);
        CONDITION_ASSERT_RETURN_VOID(retval, "Triggering condition event failed",
                                     UA_NodeId_clear(&condition);
        UA_NodeId_clear(&conditionSource););
    }
#endif /* CONDITION_SEVERITYCHANGECALLBACK_ENABLE */
    UA_NodeId_clear(&conditionSource);
    UA_NodeId_clear(&condition);
}

static UA_StatusCode
disableMethodCallback(UA_Server *server, const UA_NodeId *sessionId,
                      void *sessionContext, const UA_NodeId *methodId,
                      void *methodContext, const UA_NodeId *objectId,
                      void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize, UA_Variant *output) {
    UA_NodeId conditionTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
    if(UA_NodeId_equal(objectId, &conditionTypeNodeId)) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot call method of ConditionType Node. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADNODEIDINVALID));
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    /* Check if enabled */
    if(!UA_Server_isTwoStateVariableInTrueState(server, objectId, &fieldEnabledStateQN))
        return UA_STATUSCODE_BADCONDITIONALREADYDISABLED;

    /* Disable by writing false to EnabledState/Id--> will cause a callback to
     * trigger the new events */
    UA_Variant value;
    UA_Boolean idValue = false;
    UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
    UA_StatusCode retval =
        UA_Server_setConditionVariableFieldProperty(server, *objectId, &value,
                                                    fieldEnabledStateQN, twoStateVariableIdQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Disable Condition failed",);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
enableMethodCallback(UA_Server *server, const UA_NodeId *sessionId,
                     void *sessionContext, const UA_NodeId *methodId,
                     void *methodContext, const UA_NodeId *objectId,
                     void *objectContext, size_t inputSize,
                     const UA_Variant *input, size_t outputSize,
                     UA_Variant *output) {
    UA_NodeId conditionTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
    if(UA_NodeId_equal(objectId, &conditionTypeNodeId)) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot call method of ConditionType Node. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADNODEIDINVALID));
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    /* Check if disabled */
    if(UA_Server_isTwoStateVariableInTrueState(server, objectId, &fieldEnabledStateQN))
        return UA_STATUSCODE_BADCONDITIONALREADYENABLED;

    /* Enable by writing true to EnabledStateId--> will cause a callback to
     * trigger the new events */
    UA_Variant value;
    UA_Boolean idValue = true;
    UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
    UA_StatusCode retval =
        UA_Server_setConditionVariableFieldProperty(server, *objectId, &value,
                                                    fieldEnabledStateQN, twoStateVariableIdQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Enable Condition failed",);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addCommentMethodCallback(UA_Server *server, const UA_NodeId *sessionId,
                         void *sessionContext, const UA_NodeId *methodId,
                         void *methodContext, const UA_NodeId *objectId,
                         void *objectContext, size_t inputSize,
                         const UA_Variant *input, size_t outputSize,
                         UA_Variant *output) {
    UA_EventLoop *el = server->config.eventLoop;

    UA_QualifiedName fieldComment = UA_QUALIFIEDNAME(0, CONDITION_FIELD_COMMENT);
    UA_QualifiedName fieldSourceTimeStamp =
        UA_QUALIFIEDNAME(0, CONDITION_FIELD_CONDITIONVARIABLE_SOURCETIMESTAMP);
    UA_LocalizedText message;
    UA_NodeId triggerEvent;
    UA_Variant value;
    UA_DateTime fieldSourceTimeStampValue = el->dateTime_now(el);

    UA_NodeId conditionTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
    if(UA_NodeId_equal(objectId, &conditionTypeNodeId)) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot call method of ConditionType Node. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADNODEIDINVALID));
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    /* Get condition branch to trigger the correct event.
     * see error code Bad_NodeIdInvalid Table 16 p.22. It should be returned when the
     * Method called is from the ConditionType and not its instance, however
     * in current implementation, methods are only being referenced from their ObjectType Node.
     * Because of that, the correct instance (Condition) will be found through
     * its last EventId */
    UA_StatusCode retval =
        UA_Server_getConditionBranchNodeId(server, (UA_ByteString *)input[0].data,
                                           &triggerEvent);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "ConditionId based on EventId not found",);

    /* Check if enabled */
    if(!UA_Server_isRetained(server, &triggerEvent))
        return UA_STATUSCODE_BADCONDITIONDISABLED;

    /* Set SourceTimestamp */
    UA_Variant_setScalar(&value, &fieldSourceTimeStampValue, &UA_TYPES[UA_TYPES_DATETIME]);
    retval = UA_Server_setConditionVariableFieldProperty(server, triggerEvent, &value,
                                                         fieldComment, fieldSourceTimeStamp);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition EnabledState text failed",
                                   UA_NodeId_clear(&triggerEvent););

    /* Set adding comment time (the same value of SourceTimestamp) */
    retval = UA_Server_writeObjectProperty_scalar(server, triggerEvent, fieldTimeQN,
                                                  &fieldSourceTimeStampValue,
                                                  &UA_TYPES[UA_TYPES_DATETIME]);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set enabling/disabling Time failed",
                                   UA_NodeId_clear(&triggerEvent););

    /* Set Message */
    message = UA_LOCALIZEDTEXT(LOCALE, COMMENT_MESSAGE);
    UA_Variant_setScalar(&value, &message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = UA_Server_setConditionField(server, triggerEvent, &value, fieldMessageQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition Message failed",
                                   UA_NodeId_clear(&triggerEvent););

    /* Set Comment. Check whether comment is empty -> leave the last value as is*/
    UA_LocalizedText *inputComment = (UA_LocalizedText *)input[1].data;
    UA_String nullString = UA_STRING_NULL;
    if(!UA_String_equal(&inputComment->locale, &nullString) &&
       !UA_String_equal(&inputComment->text, &nullString)) {
        UA_Variant_setScalar(&value, inputComment, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = UA_Server_setConditionField(server, triggerEvent, &value, fieldComment);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition Comment failed",
                                       UA_NodeId_clear(&triggerEvent););
    }

    /* Get conditionSource */
    UA_NodeId conditionSource;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &triggerEvent,
                                                      fieldSourceQN, &conditionSource);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "ConditionSource not found",
                                   UA_NodeId_clear(&triggerEvent););

    /* Trigger event */
    //Condition Nodes should not be deleted after triggering the event
    retval = UA_Server_triggerConditionEvent(server, triggerEvent, conditionSource, NULL);
    UA_NodeId_clear(&conditionSource);
    UA_NodeId_clear(&triggerEvent);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Triggering condition event failed",);
    return retval;
}

static UA_StatusCode
acknowledgeMethodCallback(UA_Server *server, const UA_NodeId *sessionId,
                          void *sessionContext, const UA_NodeId *methodId,
                          void *methodContext, const UA_NodeId *objectId,
                          void *objectContext, size_t inputSize,
                          const UA_Variant *input, size_t outputSize,
                          UA_Variant *output) {
    UA_QualifiedName fieldComment = UA_QUALIFIEDNAME(0, CONDITION_FIELD_COMMENT);
    UA_Variant value;

    UA_NodeId conditionTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
    if(UA_NodeId_equal(objectId, &conditionTypeNodeId)) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot call method of ConditionType Node. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADNODEIDINVALID));
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    /* Get condition branch to trigger the correct event */
    UA_NodeId conditionNode;
    UA_StatusCode retval =
        UA_Server_getConditionBranchNodeId(server, (UA_ByteString *)input[0].data,
                                           &conditionNode);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "ConditionId based on EventId not found",);

    /* Check if retained */
    if(!UA_Server_isRetained(server, &conditionNode))
        return UA_STATUSCODE_BADCONDITIONDISABLED;

    /* Check if already acknowledged */
    if(UA_Server_isTwoStateVariableInTrueState(server, &conditionNode, &fieldAckedStateQN))
        return UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED;

    /* Get EventType */
    UA_NodeId eventType;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &conditionNode,
                                                      UA_QUALIFIEDNAME(0, CONDITION_FIELD_EVENTTYPE),
                                                      &eventType);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "EventType not found",
                                   UA_NodeId_clear(&conditionNode););

    /* Check if ConditionType is subType of AcknowledgeableConditionType TODO Over Kill*/
    UA_NodeId AcknowledgeableConditionTypeId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_ACKNOWLEDGEABLECONDITIONTYPE);
    lockServer(server);
    UA_Boolean found = isNodeInTree_singleRef(server, &eventType, &AcknowledgeableConditionTypeId,
                                              UA_REFERENCETYPEINDEX_HASSUBTYPE);
    unlockServer(server);
    if(!found) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Condition Type must be a subtype of AcknowledgeableConditionType!");
        UA_NodeId_clear(&conditionNode);
        UA_NodeId_clear(&eventType);
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    UA_NodeId_clear(&eventType);

    /* Set Comment. Check whether comment is empty -> leave the last value as is*/
    UA_LocalizedText *inputComment = (UA_LocalizedText *)input[1].data;
    UA_String nullString = UA_STRING_NULL;
    if(!UA_String_equal(&inputComment->locale, &nullString) &&
       !UA_String_equal(&inputComment->text, &nullString)) {
        UA_Variant_setScalar(&value, inputComment, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = UA_Server_setConditionField(server, conditionNode, &value, fieldComment);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition Comment failed",
                                       UA_NodeId_clear(&conditionNode););
    }

    /* Set AcknowledgeableStateId */
    UA_Boolean idValue = true;
    UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
    retval = UA_Server_setConditionVariableFieldProperty(server, conditionNode, &value,
                                               fieldAckedStateQN, twoStateVariableIdQN);
    UA_NodeId_clear(&conditionNode);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Acknowledge Condition failed",);
    return retval;
}

#ifdef CONDITIONOPTIONALFIELDS_SUPPORT
static UA_StatusCode
confirmMethodCallback(UA_Server *server, const UA_NodeId *sessionId,
                      void *sessionContext, const UA_NodeId *methodId,
                      void *methodContext, const UA_NodeId *objectId,
                      void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize,
                      UA_Variant *output) {
    UA_QualifiedName fieldComment = UA_QUALIFIEDNAME(0, CONDITION_FIELD_COMMENT);
    UA_Variant value;

    UA_NodeId conditionTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
    if(UA_NodeId_equal(objectId, &conditionTypeNodeId)) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot call method of ConditionType Node. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADNODEIDINVALID));
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    /* Get condition branch to trigger the correct event */
    UA_NodeId conditionNode;
    UA_StatusCode retval =
        UA_Server_getConditionBranchNodeId(server, (UA_ByteString *)input[0].data,
                                           &conditionNode);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "ConditionId based on EventId not found",);

    /* Check if retained */
    if(!UA_Server_isRetained(server, &conditionNode))
        return UA_STATUSCODE_BADCONDITIONDISABLED;

    /* Check if already confirmed */
    if(UA_Server_isTwoStateVariableInTrueState(server, &conditionNode, &fieldConfirmedStateQN))
        return UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED;

    /* Get EventType */
    UA_NodeId eventType;
    retval = UA_Server_getNodeIdValueOfConditionField(server, &conditionNode,
                                                      UA_QUALIFIEDNAME(0, CONDITION_FIELD_EVENTTYPE),
                                                      &eventType);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "EventType not found",
                                   UA_NodeId_clear(&conditionNode););

    /* Check if ConditionType is subType of AcknowledgeableConditionType. */
    UA_NodeId AcknowledgeableConditionTypeId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_ACKNOWLEDGEABLECONDITIONTYPE);
    lockServer(server);
    UA_Boolean found = isNodeInTree_singleRef(server, &eventType, &AcknowledgeableConditionTypeId,
                                              UA_REFERENCETYPEINDEX_HASSUBTYPE);
    unlockServer(server);
    if(!found) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Condition Type must be a subtype of AcknowledgeableConditionType!");
        UA_NodeId_clear(&conditionNode);
        UA_NodeId_clear(&eventType);
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    UA_NodeId_clear(&eventType);

    /* Set Comment. Check whether comment is empty -> leave the last value as is*/
    UA_LocalizedText *inputComment = (UA_LocalizedText *)input[1].data;
    UA_String nullString = UA_STRING_NULL;
    if(!UA_String_equal(&inputComment->locale, &nullString) &&
       !UA_String_equal(&inputComment->text, &nullString)) {
        UA_Variant_setScalar(&value, inputComment, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = UA_Server_setConditionField(server, conditionNode, &value, fieldComment);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition Comment failed",
                                       UA_NodeId_clear(&conditionNode););
    }

    /* Set ConfirmedStateId */
    UA_Boolean idValue = true;
    UA_Variant_setScalar(&value, &idValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
    retval = UA_Server_setConditionVariableFieldProperty(server, conditionNode, &value,
                                                         fieldConfirmedStateQN,
                                                         twoStateVariableIdQN);
    UA_NodeId_clear(&conditionNode);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Acknowledge Condition failed",);
    return retval;
}
#endif /* CONDITIONOPTIONALFIELDS_SUPPORT */

static UA_Boolean
isConditionSourceInMonitoredItem(UA_Server *server, const UA_MonitoredItem *monitoredItem,
                                 const UA_NodeId *conditionSource){
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* TODO: check also other hierarchical references */
    UA_ReferenceTypeSet refs = UA_REFTYPESET(UA_REFERENCETYPEINDEX_ORGANIZES);
    UA_ReferenceTypeSet_add(&refs, UA_REFERENCETYPEINDEX_HASCOMPONENT);
    UA_ReferenceTypeSet_add(&refs, UA_REFERENCETYPEINDEX_HASEVENTSOURCE);
    UA_ReferenceTypeSet_add(&refs, UA_REFERENCETYPEINDEX_HASNOTIFIER);
    return isNodeInTree(server, conditionSource, &monitoredItem->itemToMonitor.nodeId, &refs);
}

static UA_StatusCode
refreshLogic(UA_Server *server, UA_Session *session,
             UA_Subscription *sub, UA_MonitoredItem *monitoredItem) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_assert(monitoredItem != NULL);

    /* 1. Trigger RefreshStartEvent */
    UA_EventDescription ed = {0};
    ed.sourceNode = UA_NS0ID(SERVER);
    ed.eventType = UA_NS0ID(REFRESHSTARTEVENTTYPE);
    ed.severity = REFRESHEVENT_SEVERITY_DEFAULT;
    ed.sessionId = &session->sessionId;
    ed.subscriptionId = &sub->subscriptionId;
    ed.monitoredItemId = (monitoredItem) ? &monitoredItem->monitoredItemId : NULL;
    UA_StatusCode retval = createEvent(server, &ed, NULL);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Events: Could not add the event to a listening node",);

    /* 2. Refresh (see 5.5.7) */
    /* Get ConditionSource Entry */
    UA_ConditionSource *source;
    LIST_FOREACH(source, &server->conditionSources, listEntry) {
        UA_NodeId conditionSource = source->conditionSourceId;
        UA_NodeId serverObjectNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
        /* Check if the conditionSource is being monitored. If the Server Object
         * is being monitored, then all Events of all monitoredItems should be
         * refreshed */
        if(!UA_NodeId_equal(&monitoredItem->itemToMonitor.nodeId, &conditionSource) &&
           !UA_NodeId_equal(&monitoredItem->itemToMonitor.nodeId, &serverObjectNodeId) &&
           !isConditionSourceInMonitoredItem(server, monitoredItem, &conditionSource))
            continue;

        /* Get Condition Entry */
        UA_Condition *cond;
        LIST_FOREACH(cond, &source->conditions, listEntry) {
            /* Get Branch Entry */
            UA_ConditionBranch *branch;
            LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
                /* If no event was triggered for that branch, then check next
                 * without refreshing */
                if(UA_ByteString_equal(&branch->lastEventId, &UA_BYTESTRING_NULL))
                    continue;

                UA_NodeId triggeredNode;
                if(UA_NodeId_isNull(&branch->conditionBranchId))
                    triggeredNode = cond->conditionId;
                else
                    triggeredNode = branch->conditionBranchId;

                /* Check if Retain is set to true */
                if(!isRetained(server, &triggeredNode))
                    continue;

                UA_ByteString_clear(&branch->lastEventId);

                /* Add the event */
                ed.eventInstance = &triggeredNode;
                ed.sourceNode = conditionSource;
                ed.eventType = UA_NODEID_NULL; /* overwritten by the EventInstance */
                retval = createEvent(server, &ed, &branch->lastEventId);
                CONDITION_ASSERT_RETURN_RETVAL(retval, "Events: Could not add the event to a listening node",);
            }
        }
    }

    /* 3. Trigger RefreshEndEvent */
    ed.eventInstance = NULL;
    ed.sourceNode = UA_NS0ID(SERVER);
    ed.eventType = UA_NS0ID(REFRESHENDEVENTTYPE);
    return createEvent(server, &ed, NULL);
}

static UA_StatusCode
refresh2MethodCallback(UA_Server *server, const UA_NodeId *sessionId,
                      void *sessionContext, const UA_NodeId *methodId,
                      void *methodContext, const UA_NodeId *objectId,
                      void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize,
                      UA_Variant *output) {
    lockServer(server);
    //TODO implement logic for subscription array
    /* Check if valid subscriptionId */
    UA_Session *session = getSessionById(server, sessionId);
    UA_Subscription *subscription =
        UA_Session_getSubscriptionById(session, *((UA_UInt32 *)input[0].data));
    if(!subscription) {
        unlockServer(server);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* Trigger RefreshStartEvent and RefreshEndEvent for the each monitoredItem
     * in the subscription */
    UA_MonitoredItem *monitoredItem =
        UA_Subscription_getMonitoredItem(subscription, *((UA_UInt32 *)input[1].data));
    if(!monitoredItem) {
        unlockServer(server);
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    }

    // TODO when there are a lot of monitoreditems (not only events)?
    UA_StatusCode retval = refreshLogic(server, session, subscription, monitoredItem);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Could not refresh Condition",
                                   unlockServer(server););
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
refreshMethodCallback(UA_Server *server, const UA_NodeId *sessionId,
                      void *sessionContext, const UA_NodeId *methodId,
                      void *methodContext, const UA_NodeId *objectId,
                      void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize,
                      UA_Variant *output) {
    lockServer(server);

    //TODO implement logic for subscription array
    /* Check if valid subscriptionId */
    UA_Session *session = getSessionById(server, sessionId);
    UA_Subscription *subscription =
        UA_Session_getSubscriptionById(session, *((UA_UInt32 *)input[0].data));
    if(!subscription) {
        unlockServer(server);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* Trigger RefreshStartEvent and RefreshEndEvent for the each monitoredItem
     * in the subscription */

    UA_MonitoredItem *item;
    LIST_FOREACH(item, &subscription->monitoredItems, listEntry) {
        if (item->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER)
            continue;
        UA_StatusCode retval = refreshLogic(server, session, subscription, item);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Could not refresh Condition",
                                       unlockServer(server););
    }

    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

/*****************************************************************************/
/* Functions                                                                 */
/*****************************************************************************/

static UA_StatusCode
setConditionInConditionList(UA_Server *server, const UA_NodeId *conditionNodeId,
                            UA_ConditionSource *conditionSourceEntry) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Condition *conditionListEntry = (UA_Condition*)UA_malloc(sizeof(UA_Condition));
    if(!conditionListEntry)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(conditionListEntry, 0, sizeof(UA_Condition));

    /* Set ConditionId with given ConditionNodeId */
    UA_StatusCode retval = UA_NodeId_copy(conditionNodeId, &conditionListEntry->conditionId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(conditionListEntry);
        return retval;
    }

    UA_ConditionBranch *conditionBranchListEntry;
    conditionBranchListEntry = (UA_ConditionBranch*)UA_malloc(sizeof(UA_ConditionBranch));
    if(!conditionBranchListEntry) {
        UA_free(conditionListEntry);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    memset(conditionBranchListEntry, 0, sizeof(UA_ConditionBranch));
    LIST_INSERT_HEAD(&conditionSourceEntry->conditions, conditionListEntry, listEntry);
    LIST_INSERT_HEAD(&conditionListEntry->conditionBranches, conditionBranchListEntry, listEntry);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
appendConditionEntry(UA_Server *server, const UA_NodeId *conditionNodeId,
                     const UA_NodeId *conditionSourceNodeId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* See if the ConditionSource Entry already exists*/
    UA_ConditionSource *source = getConditionSource(server, conditionSourceNodeId);
    if(source)
        return setConditionInConditionList(server, conditionNodeId, source);

    /* ConditionSource not found in list, so we create a new ConditionSource Entry */
    UA_ConditionSource *conditionSourceListEntry;
    conditionSourceListEntry = (UA_ConditionSource*)UA_malloc(sizeof(UA_ConditionSource));
    if(!conditionSourceListEntry)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(conditionSourceListEntry, 0, sizeof(UA_ConditionSource));

    /* Set ConditionSourceId with given ConditionSourceNodeId */
    UA_StatusCode retval = UA_NodeId_copy(conditionSourceNodeId,
                                          &conditionSourceListEntry->conditionSourceId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(conditionSourceListEntry);
        return retval;
    }

    LIST_INSERT_HEAD(&server->conditionSources, conditionSourceListEntry, listEntry);
    return setConditionInConditionList(server, conditionNodeId, conditionSourceListEntry);
}

static void
deleteAllBranchesFromCondition(UA_Condition *cond) {
    UA_ConditionBranch *branch, *tmp_branch;
    LIST_FOREACH_SAFE(branch, &cond->conditionBranches, listEntry, tmp_branch) {
        UA_NodeId_clear(&branch->conditionBranchId);
        UA_ByteString_clear(&branch->lastEventId);
        LIST_REMOVE(branch, listEntry);
        UA_free(branch);
    }
}

static void
deleteCondition(UA_Condition *cond) {
    deleteAllBranchesFromCondition(cond);
    UA_NodeId_clear(&cond->conditionId);
    LIST_REMOVE(cond, listEntry);
    UA_free(cond);
}

void
UA_ConditionList_delete(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_ConditionSource *source, *tmp_source;
    LIST_FOREACH_SAFE(source, &server->conditionSources, listEntry, tmp_source) {
        UA_Condition *cond, *tmp_cond;
        LIST_FOREACH_SAFE(cond, &source->conditions, listEntry, tmp_cond) {
            deleteCondition(cond);
        }
        UA_NodeId_clear(&source->conditionSourceId);
        LIST_REMOVE(source, listEntry);
        UA_free(source);
    }
}

/* Get the ConditionId based on the EventId (all branches of one condition
 * should have the same ConditionId) */
UA_StatusCode
UA_getConditionId(UA_Server *server, const UA_NodeId *conditionNodeId,
                  UA_NodeId *outConditionId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get ConditionSource Entry */
    UA_ConditionSource *source;
    LIST_FOREACH(source, &server->conditionSources, listEntry) {
        /* Get Condition Entry */
        UA_Condition *cond;
        LIST_FOREACH(cond, &source->conditions, listEntry) {
            if(UA_NodeId_equal(&cond->conditionId, conditionNodeId)) {
                *outConditionId = cond->conditionId;
                return UA_STATUSCODE_GOOD;
            }
            /* Get Branch Entry*/
            UA_ConditionBranch *branch;
            LIST_FOREACH(branch, &cond->conditionBranches, listEntry) {
                if(UA_NodeId_equal(&branch->conditionBranchId, conditionNodeId)) {
                    *outConditionId = cond->conditionId;
                    return UA_STATUSCODE_GOOD;
                }
            }
        }
    }
    return UA_STATUSCODE_BADNOTFOUND;
}

/* Check whether the Condition Source Node has "EventSource" or one of its
 * subtypes inverse reference. */
static UA_Boolean
doesHasEventSourceReferenceExist(UA_Server *server, const UA_NodeId nodeToCheck) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId hasEventSourceId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE);
    const UA_Node* node = UA_NODESTORE_GET(server, &nodeToCheck);
    if(!node)
        return false;
    for(size_t i = 0; i < node->head.referencesSize; i++) {
        UA_Byte refTypeIndex = node->head.references[i].referenceTypeIndex;
        if((refTypeIndex == UA_REFERENCETYPEINDEX_HASEVENTSOURCE ||
            isNodeInTree_singleRef(server, UA_NODESTORE_GETREFERENCETYPEID(server, refTypeIndex),
                                   &hasEventSourceId, UA_REFERENCETYPEINDEX_HASSUBTYPE)) &&
           (node->head.references[i].isInverse == true)) {
            UA_NODESTORE_RELEASE(server, node);
            return true;
        }
    }
    UA_NODESTORE_RELEASE(server, node);
    return false;
}

static UA_StatusCode
setStandardConditionFields(UA_Server *server, const UA_NodeId* condition,
                           const UA_NodeId* conditionType, const UA_NodeId* conditionSource,
                           const UA_QualifiedName* conditionName) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Set Fields */
    /* 1.Set EventType */
    UA_Variant value;
    UA_Variant_setScalar(&value, (void*)(uintptr_t)conditionType, &UA_TYPES[UA_TYPES_NODEID]);
    UA_StatusCode retval = setConditionField(server, *condition, &value,
                                             UA_QUALIFIEDNAME(0,CONDITION_FIELD_EVENTTYPE));
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set EventType Field failed",);

    /* 2.Set ConditionName */
    UA_Variant_setScalar(&value, (void*)(uintptr_t)&conditionName->name,
                         &UA_TYPES[UA_TYPES_STRING]);
    retval = setConditionField(server, *condition, &value,
                               UA_QUALIFIEDNAME(0,CONDITION_FIELD_CONDITIONNAME));
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set ConditionName Field failed",);

    /* 3.Set EnabledState (Disabled by default -> Retain Field = false) */
    UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, DISABLED_TEXT);
    UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = setConditionField(server, *condition, &value,
                               UA_QUALIFIEDNAME(0,CONDITION_FIELD_ENABLEDSTATE));
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set EnabledState Field failed",);

    /* 4.Set EnabledState/Id */
    UA_Boolean stateId = false;
    UA_Variant_setScalar(&value, &stateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
    retval = setConditionVariableFieldProperty(server, *condition, &value,
                                               UA_QUALIFIEDNAME(0,CONDITION_FIELD_ENABLEDSTATE),
                                               twoStateVariableIdQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set EnabledState/Id Field failed",);

    /* 5.Set Retain*/
    UA_Variant_setScalar(&value, &stateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
    retval = setConditionField(server, *condition, &value, fieldRetainQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Retain Field failed",);

    /* Get ConditionSourceNode*/
    const UA_Node *conditionSourceNode = UA_NODESTORE_GET(server, conditionSource);
    if(!conditionSourceNode) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Couldn't find ConditionSourceNode. StatusCode %s", UA_StatusCode_name(retval));
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* 6.Set SourceName*/
    UA_Variant_setScalar(&value, (void*)(uintptr_t)&conditionSourceNode->head.browseName.name,
                         &UA_TYPES[UA_TYPES_STRING]);
    retval = setConditionField(server, *condition, &value,
                               UA_QUALIFIEDNAME(0,CONDITION_FIELD_SOURCENAME));
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Set SourceName Field failed. StatusCode %s",
                     UA_StatusCode_name(retval));
        UA_NODESTORE_RELEASE(server, conditionSourceNode);
        return retval;
    }

    /* 7.Set SourceNode*/
    UA_Variant_setScalar(&value, (void*)(uintptr_t)&conditionSourceNode->head.nodeId,
                         &UA_TYPES[UA_TYPES_NODEID]);
    retval = setConditionField(server, *condition, &value, fieldSourceQN);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Set SourceNode Field failed. StatusCode %s", UA_StatusCode_name(retval));
        UA_NODESTORE_RELEASE(server, conditionSourceNode);
        return retval;
    }

    UA_NODESTORE_RELEASE(server, conditionSourceNode);

    /* 8. Set Quality (TODO not supported, thus set with Status Good) */
    UA_StatusCode qualityValue = UA_STATUSCODE_GOOD;
    UA_Variant_setScalar(&value, &qualityValue, &UA_TYPES[UA_TYPES_STATUSCODE]);
    retval = setConditionField(server, *condition, &value,
                               UA_QUALIFIEDNAME(0,CONDITION_FIELD_QUALITY));
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Quality Field failed",);

    /* 9. Set Severity */
    UA_UInt16 severityValue = 0;
    UA_Variant_setScalar(&value, &severityValue, &UA_TYPES[UA_TYPES_UINT16]);
    retval = setConditionField(server, *condition, &value,
                               UA_QUALIFIEDNAME(0,CONDITION_FIELD_SEVERITY));
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Severity Field failed",);

    /* Check subTypes of ConditionType to set further Fields*/

    /* 1. Check if ConditionType is subType of AcknowledgeableConditionType */
    UA_NodeId acknowledgeableConditionTypeId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_ACKNOWLEDGEABLECONDITIONTYPE);
    if(!isNodeInTree_singleRef(server, conditionType, &acknowledgeableConditionTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return UA_STATUSCODE_GOOD;

    /* Set AckedState (Id = false by default) */
    text = UA_LOCALIZEDTEXT(LOCALE, UNACKED_TEXT);
    UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = setConditionField(server, *condition, &value, fieldAckedStateQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set AckedState Field failed",);

    UA_Variant_setScalar(&value, &stateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
    retval = setConditionVariableFieldProperty(server, *condition, &value,
                                               fieldAckedStateQN, twoStateVariableIdQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set AckedState/Id Field failed",);

#ifdef CONDITIONOPTIONALFIELDS_SUPPORT
    /* add optional field ConfirmedState*/
    retval = addConditionOptionalField(server, *condition, acknowledgeableConditionTypeId,
                                       fieldConfirmedStateQN, NULL);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding ConfirmedState optional Field failed",);

    /* Set ConfirmedState (Id = false by default) */
    text = UA_LOCALIZEDTEXT(LOCALE, UNCONFIRMED_TEXT);
    UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval = setConditionField(server, *condition, &value, fieldConfirmedStateQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set ConfirmedState Field failed",);

    UA_Variant_setScalar(&value, &stateId, &UA_TYPES[UA_TYPES_BOOLEAN]);
    retval = setConditionVariableFieldProperty(server, *condition, &value,
                                               fieldConfirmedStateQN,
                                               twoStateVariableIdQN);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set EnabledState/Id Field failed",);

    /* Add  optional property for certificate expiration alarm type*/
    UA_NodeId certificateConditionTypeId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_CERTIFICATEEXPIRATIONALARMTYPE);
    if(isNodeInTree_singleRef(server, conditionType, &certificateConditionTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
        retval = addConditionOptionalField(server, *condition, certificateConditionTypeId,
                                           fieldExpirationLimitQN, NULL);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding Expiration Limit optional field failed",);

        /* Set the default value for the Expiration limit property */
        UA_Duration defaultValue = EXPIRATION_LIMIT_DEFAULT_VALUE;
        retval |= writeObjectProperty_scalar(server, *condition, fieldExpirationLimitQN,
                                             &defaultValue, &UA_TYPES[UA_TYPES_DURATION]);

    }

#endif /* CONDITIONOPTIONALFIELDS_SUPPORT */

    /* 2. Check if ConditionType is subType of AlarmConditionType */
    UA_NodeId alarmConditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ALARMCONDITIONTYPE);
    if(isNodeInTree_singleRef(server, conditionType, &alarmConditionTypeId,
                              UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
        /* Set ActiveState (Id = false by default) */
        text = UA_LOCALIZEDTEXT(LOCALE, INACTIVE_TEXT);
        UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        retval = setConditionField(server, *condition, &value,
                                   UA_QUALIFIEDNAME(0,CONDITION_FIELD_ACTIVESTATE));
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set ActiveState Field failed",);
    }

#ifdef CONDITIONOPTIONALFIELDS_SUPPORT
    /* 3. Check if the ConditionType is subType of LimitAlarmType */
    UA_NodeId LimitAlarmTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_LIMITALARMTYPE);
    if(!isNodeInTree_singleRef(server, conditionType, &LimitAlarmTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return retval;

    /* Set optional field property. For the LimitAlarm and its subtypes, atleast
     * one limit is mandatory */
    /* Add optional field LowLimit */
    retval = addConditionOptionalField(server, *condition, LimitAlarmTypeId,
                                       fieldLowLimitQN, NULL);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding LowLimit optional Field failed",);

    /* Add optional field HighLimit */
    retval = addConditionOptionalField(server, *condition, LimitAlarmTypeId,
                                       fieldHighLimitQN, NULL);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding HighLimit optional Field failed",);

    /* Add optional field HighHighLimit */
    retval = addConditionOptionalField(server, *condition, LimitAlarmTypeId,
                                       fieldHighHighLimitQN, NULL);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding HighLimit optional Field failed",);

    /* Add optional field LowLowLimit */
    retval = addConditionOptionalField(server, *condition, LimitAlarmTypeId,
                                       fieldLowLowLimitQN, NULL);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding LowLowLimit optional Field failed",);

    /* 4. Check if the ConditionType is subType of RateOfChangeAlarmType */
    UA_NodeId RateOfChangeAlarmTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_EXCLUSIVERATEOFCHANGEALARMTYPE);
    if(!isNodeInTree_singleRef(server, conditionType, &RateOfChangeAlarmTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return retval;

    retval = addConditionOptionalField(server, *condition, RateOfChangeAlarmTypeId,
                                       fieldEngineeringUnitsQN, NULL);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding EngineeringUnit optional Field failed",);

#endif /* CONDITIONOPTIONALFIELDS_SUPPORT */

    return retval;
}

/* Set callbacks for TwoStateVariable Fields of a condition */
static UA_StatusCode
setTwoStateVariableCallbacks(UA_Server *server, const UA_NodeId* condition,
                             const UA_NodeId* conditionType) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Set EnabledState Callback */
    UA_NodeId twoStateVariableIdNodeId = UA_NODEID_NULL;
    UA_StatusCode retval = getConditionFieldPropertyNodeId(server, condition, &fieldEnabledStateQN,
                                                           &twoStateVariableIdQN,
                                                           &twoStateVariableIdNodeId);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Id Property of TwoStateVariable not found",);

    UA_ValueSourceNotifications callback;
    callback.onRead = NULL;
    callback.onWrite = afterWriteCallbackEnabledStateChange;
    retval = setVariableNode_internalValueSource(server, twoStateVariableIdNodeId,
                                                 NULL, &callback);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set EnabledState Callback failed",
                                   UA_NodeId_clear(&twoStateVariableIdNodeId););

    /* Set AckedState Callback */
    /* Check if ConditionType is subType of AcknowledgeableConditionType */
    UA_NodeId acknowledgeableConditionTypeId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_ACKNOWLEDGEABLECONDITIONTYPE);
    if(isNodeInTree_singleRef(server, conditionType, &acknowledgeableConditionTypeId,
                              UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
        UA_NodeId_clear(&twoStateVariableIdNodeId);
        retval = getConditionFieldPropertyNodeId(server, condition, &fieldAckedStateQN,
                                                 &twoStateVariableIdQN, &twoStateVariableIdNodeId);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Id Property of TwoStateVariable not found",);

        callback.onWrite = afterWriteCallbackAckedStateChange;
        retval = setVariableNode_internalValueSource(server, twoStateVariableIdNodeId,
                                                     NULL, &callback);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set AckedState Callback failed",
                                       UA_NodeId_clear(&twoStateVariableIdNodeId););

#ifdef CONDITIONOPTIONALFIELDS_SUPPORT
        /* add callback */
        callback.onWrite = afterWriteCallbackConfirmedStateChange;
        UA_NodeId_clear(&twoStateVariableIdNodeId);
        retval = getConditionFieldPropertyNodeId(server, condition, &fieldConfirmedStateQN,
                                                 &twoStateVariableIdQN, &twoStateVariableIdNodeId);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Id Property of TwoStateVariable not found",);

        /* add reference from Condition to Confirm Method */
        UA_NodeId hasComponent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);
        UA_NodeId confirm = UA_NODEID_NUMERIC(0, UA_NS0ID_ACKNOWLEDGEABLECONDITIONTYPE_CONFIRM);
        retval = addRef(server, *condition, hasComponent, confirm, true);
        CONDITION_ASSERT_RETURN_RETVAL(retval,
                                       "Adding HasComponent Reference to Confirm Method failed",
                                       UA_NodeId_clear(&twoStateVariableIdNodeId););

        retval = setVariableNode_internalValueSource(server, twoStateVariableIdNodeId,
                                                     NULL, &callback);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding ConfirmedState/Id callback failed",
                                       UA_NodeId_clear(&twoStateVariableIdNodeId););
#endif /* CONDITIONOPTIONALFIELDS_SUPPORT */

        /* Set ActiveState Callback */
        /* Check if ConditionType is subType of AlarmConditionType */
        UA_NodeId alarmConditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ALARMCONDITIONTYPE);
        if(isNodeInTree_singleRef(server, conditionType, &alarmConditionTypeId,
                                  UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
            UA_NodeId_clear(&twoStateVariableIdNodeId);
            retval = getConditionFieldPropertyNodeId(server, condition, &fieldActiveStateQN,
                                                     &twoStateVariableIdQN, &twoStateVariableIdNodeId);
            CONDITION_ASSERT_RETURN_RETVAL(retval, "Id Property of TwoStateVariable not found",);

            callback.onWrite = afterWriteCallbackActiveStateChange;
            retval = setVariableNode_internalValueSource(server, twoStateVariableIdNodeId,
                                                         NULL, &callback);
            CONDITION_ASSERT_RETURN_RETVAL(retval, "Set ActiveState Callback failed",
                                           UA_NodeId_clear(&twoStateVariableIdNodeId););
        }
    }

    UA_NodeId_clear(&twoStateVariableIdNodeId);
    return retval;
}

/* Set callbacks for ConditionVariable Fields of a condition */
static UA_StatusCode
setConditionVariableCallbacks(UA_Server *server, const UA_NodeId *condition,
                              const UA_NodeId *conditionType) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_QualifiedName conditionVariableName[2] = {
        UA_QUALIFIEDNAME(0, CONDITION_FIELD_QUALITY),
        UA_QUALIFIEDNAME(0, CONDITION_FIELD_SEVERITY)
    };// extend array with other fields when needed

    UA_BrowsePathResult bpr =
        browseSimplifiedBrowsePath(server, *condition, 1, &conditionVariableName[0]);
    if(bpr.statusCode != UA_STATUSCODE_GOOD)
        return bpr.statusCode;
    UA_ValueSourceNotifications callback ;
    callback.onRead = NULL;
    callback.onWrite = afterWriteCallbackQualityChange;
    retval = setVariableNode_internalValueSource(server, bpr.targets[0].targetId.nodeId,
                                                 NULL, &callback);
    UA_BrowsePathResult_clear(&bpr);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    bpr = browseSimplifiedBrowsePath(server, *condition, 1, &conditionVariableName[1]);
    if(bpr.statusCode != UA_STATUSCODE_GOOD)
        return bpr.statusCode;
    callback.onWrite = afterWriteCallbackSeverityChange;
    retval = setVariableNode_internalValueSource(server, bpr.targets[0].targetId.nodeId,
                                                 NULL, &callback);
    UA_BrowsePathResult_clear(&bpr);
    return retval;
}

/* Set callbacks for Method Fields of a condition. The current implementation
 * references methods without copying them when creating objects. So the
 * callbacks will be attached to the methods of the conditionType. */
static UA_StatusCode
setConditionMethodCallbacks(UA_Server *server, const UA_NodeId* condition,
                            const UA_NodeId* conditionType) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId methodId[7] = {
        {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_CONDITIONTYPE_DISABLE}},
        {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_CONDITIONTYPE_ENABLE}},
        {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_CONDITIONTYPE_ADDCOMMENT}},
        {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_CONDITIONTYPE_CONDITIONREFRESH}},
        {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_CONDITIONTYPE_CONDITIONREFRESH2}},
        {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ACKNOWLEDGEABLECONDITIONTYPE_ACKNOWLEDGE}}
#ifdef CONDITIONOPTIONALFIELDS_SUPPORT
        ,{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ACKNOWLEDGEABLECONDITIONTYPE_CONFIRM}}
#endif
    };

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    retval |= setMethodNode_callback(server, methodId[0], disableMethodCallback);
    retval |= setMethodNode_callback(server, methodId[1], enableMethodCallback);
    retval |= setMethodNode_callback(server, methodId[2], addCommentMethodCallback);
    retval |= setMethodNode_callback(server, methodId[3], refreshMethodCallback);
    retval |= setMethodNode_callback(server, methodId[4], refresh2MethodCallback);
    retval |= setMethodNode_callback(server, methodId[5], acknowledgeMethodCallback);
#ifdef CONDITIONOPTIONALFIELDS_SUPPORT
    retval |= setMethodNode_callback(server, methodId[6], confirmMethodCallback);
#endif

    return retval;
}

static UA_StatusCode
setStandardConditionCallbacks(UA_Server *server, const UA_NodeId* condition,
                              const UA_NodeId* conditionType) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retval = setTwoStateVariableCallbacks(server, condition, conditionType);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set TwoStateVariable Callback failed",);

    retval = setConditionVariableCallbacks(server, condition, conditionType);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set ConditionVariable Callback failed",);

    /* Set callbacks for Method Components (needs to be set only once!) */
    if(LIST_EMPTY(&server->conditionSources)) {
        retval = setConditionMethodCallbacks(server, condition, conditionType);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Method Callback failed",);
    }

    return retval;
}

static UA_StatusCode
addCondition_finish(UA_Server *server, const UA_NodeId conditionId,
                    const UA_NodeId conditionType, const UA_QualifiedName conditionName,
                    const UA_NodeId conditionSource, const UA_NodeId hierarchialReferenceType) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retval = addNode_finish(server, &server->adminSession, &conditionId);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Finish node failed",);

    /* Make sure the ConditionSource has HasEventSource or one of its SubTypes ReferenceType */
    UA_NodeId serverObject = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
    if(!doesHasEventSourceReferenceExist(server, conditionSource) &&
       !UA_NodeId_equal(&serverObject, &conditionSource)) {
         UA_NodeId hasHasEventSourceId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE);
         retval = addRef(server, serverObject, hasHasEventSourceId, conditionSource, true);
          CONDITION_ASSERT_RETURN_RETVAL(retval, "Creating HasHasEventSource Reference "
                                         "to the Server Object failed",);
    }

    /* create HasCondition Reference (HasCondition should be forward from the
     * ConditionSourceNode to the Condition. else, HasCondition should be
     * forward from the ConditionSourceNode to the ConditionType Node) */
    UA_NodeId hasCondition = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCONDITION);
    if(!UA_NodeId_isNull(&hierarchialReferenceType)) {
        /* Create hierarchical Reference to ConditionSource to expose the
         * ConditionNode in Address Space */
        // only Check hierarchialReferenceType
        retval = addRef(server, conditionSource, hierarchialReferenceType, conditionId, true);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Creating hierarchical Reference to "
                                       "ConditionSource failed",);

        retval = addRef(server, conditionSource, hasCondition, conditionId, true);
        CONDITION_ASSERT_RETURN_RETVAL(retval, "Creating HasCondition Reference failed",);
    } else {
        retval = addRef(server, conditionSource, hasCondition, conditionType, true);
        if(retval != UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED)
            CONDITION_ASSERT_RETURN_RETVAL(retval, "Creating HasCondition Reference failed",);
    }

    /* Set standard fields */
    retval = setStandardConditionFields(server, &conditionId, &conditionType,
                                        &conditionSource, &conditionName);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set standard Condition Fields failed",);

    /* Set Method Callbacks */
    retval = setStandardConditionCallbacks(server, &conditionId, &conditionType);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Set Condition callbacks failed",);

    /* change Refresh Events IsAbstract = false
     * so abstract Events : RefreshStart and RefreshEnd could be created */
    UA_NodeId refreshStartEventTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_REFRESHSTARTEVENTTYPE);
    UA_NodeId refreshEndEventTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_REFRESHENDEVENTTYPE);

    UA_Boolean startAbstract = false;
    UA_Boolean endAbstract = false;
    readWithReadValue(server, &refreshStartEventTypeNodeId,
                      UA_ATTRIBUTEID_ISABSTRACT, &startAbstract);
    readWithReadValue(server, &refreshEndEventTypeNodeId,
                      UA_ATTRIBUTEID_ISABSTRACT, &endAbstract);

    UA_Boolean inner = (startAbstract == false && endAbstract == false);
    if(inner) {
        writeIsAbstractAttribute(server, refreshStartEventTypeNodeId, false);
        writeIsAbstractAttribute(server, refreshEndEventTypeNodeId, false);
    }

    /* append Condition to list */
    return appendConditionEntry(server, &conditionId, &conditionSource);
}

/* Create condition instance. The function checks first whether the passed
 * conditionType is a subType of ConditionType. Then checks whether the
 * condition source has HasEventSource reference to its parent. If not, a
 * HasEventSource reference will be created between condition source and server
 * object. To expose the condition in address space, a hierarchical
 * ReferenceType should be passed to create the reference to condition source.
 * Otherwise, UA_NODEID_NULL should be passed to make the condition unexposed. */
UA_StatusCode
UA_Server_createCondition(UA_Server *server,
                          const UA_NodeId conditionId, const UA_NodeId conditionType,
                          const UA_QualifiedName conditionName,
                          const UA_NodeId conditionSource,
                          const UA_NodeId hierarchialReferenceType,
                          UA_NodeId *outNodeId) {
    if(!outNodeId) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "outNodeId cannot be NULL!");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = UA_Server_addCondition_begin(server, conditionId, conditionType,
                                                        conditionName, outNodeId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    lockServer(server);
    retval = addCondition_finish(server, *outNodeId, conditionType, conditionName,
                               conditionSource, hierarchialReferenceType);
    unlockServer(server);
    return retval;
}

UA_StatusCode
UA_Server_addCondition_begin(UA_Server *server, const UA_NodeId conditionId,
                             const UA_NodeId conditionType,
                             const UA_QualifiedName conditionName, UA_NodeId *outNodeId) {
    if(!outNodeId) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "outNodeId cannot be NULL!");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Make sure the conditionType is a Subtype of ConditionType */
    UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
    lockServer(server);
    UA_Boolean found = isNodeInTree_singleRef(server, &conditionType, &conditionTypeId,
                                              UA_REFERENCETYPEINDEX_HASSUBTYPE);
    unlockServer(server);
    if(!found) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Condition Type must be a subtype of ConditionType!");
        return UA_STATUSCODE_BADNOMATCH;
    }

    /* Create an ObjectNode which represents the condition */
    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
    oAttr.displayName.locale = UA_STRING("en");
    oAttr.displayName.text = conditionName.name;
    UA_StatusCode retval =
        UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, conditionId,
                                UA_NODEID_NULL, UA_NODEID_NULL, conditionName,
                                conditionType, &oAttr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                                NULL, outNodeId);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Adding Condition failed", );
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_addCondition_finish(UA_Server *server, const UA_NodeId conditionId,
                              const UA_NodeId conditionSource,
                              const UA_NodeId hierarchialReferenceType) {
    lockServer(server);

    const UA_Node *node = UA_NODESTORE_GET(server, &conditionId);

    if(!node) {
        unlockServer(server);
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    const UA_Node *type =
        getNodeType(server, &node->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
    if(!type) {
        UA_NODESTORE_RELEASE(server, node);
        unlockServer(server);
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
    }

    UA_StatusCode retval;
    retval = addCondition_finish(server, conditionId, type->head.nodeId, node->head.browseName,
                                 conditionSource, hierarchialReferenceType);

    UA_NODESTORE_RELEASE(server, type);
    UA_NODESTORE_RELEASE(server, node);

    unlockServer(server);
    return retval;
}

#ifdef CONDITIONOPTIONALFIELDS_SUPPORT

static UA_StatusCode
addOptionalVariableField(UA_Server *server, const UA_NodeId *originCondition,
                         const UA_QualifiedName *fieldName,
                         const UA_VariableNode *optionalVariableFieldNode,
                         UA_NodeId *outOptionalVariable) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_VariableAttributes vAttr = UA_VariableAttributes_default;
    vAttr.valueRank = optionalVariableFieldNode->valueRank;
    vAttr.displayName = UA_Session_getNodeDisplayName(&server->adminSession,
                                                      &optionalVariableFieldNode->head);
    vAttr.dataType = optionalVariableFieldNode->dataType;

    /* Get typedefintion */
    const UA_Node *type =
        getNodeType(server, &optionalVariableFieldNode->head,
                    ~(UA_UInt32)0, UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
    if(!type) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Invalid VariableType. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADTYPEDEFINITIONINVALID));
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
    }

    /* Set referenceType to parent */
    UA_NodeId referenceToParent;
    UA_NodeId propertyTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE);
    if(UA_NodeId_equal(&type->head.nodeId, &propertyTypeNodeId))
        referenceToParent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
    else
        referenceToParent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);

    /* Set a random unused NodeId with specified Namespace Index*/
    UA_NodeId optionalVariable = {originCondition->namespaceIndex, UA_NODEIDTYPE_NUMERIC, {0}};
    UA_StatusCode retval =
        addNode(server, UA_NODECLASS_VARIABLE, optionalVariable,
                *originCondition, referenceToParent, *fieldName,
                type->head.nodeId, &vAttr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                NULL, outOptionalVariable);
    UA_NODESTORE_RELEASE(server, type);
    return retval;
}

static UA_StatusCode
addOptionalObjectField(UA_Server *server, const UA_NodeId *originCondition,
                       const UA_QualifiedName* fieldName,
                       const UA_ObjectNode *optionalObjectFieldNode,
                       UA_NodeId *outOptionalObject) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
    oAttr.displayName = UA_Session_getNodeDisplayName(&server->adminSession,
                                                      &optionalObjectFieldNode->head);

    /* Get typedefintion */
    const UA_Node *type =
        getNodeType(server, &optionalObjectFieldNode->head, ~(UA_UInt32)0,
                    UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
    if(!type) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Invalid ObjectType. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADTYPEDEFINITIONINVALID));
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
    }

    /* Set referenceType to parent */
    UA_NodeId referenceToParent;
    UA_NodeId propertyTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE);
    if(UA_NodeId_equal(&type->head.nodeId, &propertyTypeNodeId))
        referenceToParent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
    else
        referenceToParent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);

    UA_NodeId optionalObject = {originCondition->namespaceIndex, UA_NODEIDTYPE_NUMERIC, {0}};
    UA_StatusCode retval = addNode(server, UA_NODECLASS_OBJECT, optionalObject,
                                   *originCondition, referenceToParent, *fieldName,
                                   type->head.nodeId, &oAttr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                                   NULL, outOptionalObject);
    UA_NODESTORE_RELEASE(server, type);
    return retval;
}

#endif /* CONDITIONOPTIONALFIELDS_SUPPORT */

static UA_StatusCode
addConditionOptionalField(UA_Server *server, const UA_NodeId condition,
                          const UA_NodeId conditionType, const UA_QualifiedName fieldName,
                          UA_NodeId *outOptionalNode) {
    UA_LOCK_ASSERT(&server->serviceMutex);

#ifdef CONDITIONOPTIONALFIELDS_SUPPORT
    /* Get optional Field NodId from ConditionType -> user should give the
     * correct ConditionType or Subtype!!!! */
    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, conditionType, 1, &fieldName);
    if(bpr.statusCode != UA_STATUSCODE_GOOD)
        return bpr.statusCode;

    /* Get Node */
    UA_NodeId optionalFieldNodeId = bpr.targets[0].targetId.nodeId;
    const UA_Node *optionalFieldNode = UA_NODESTORE_GET(server, &optionalFieldNodeId);
    if(NULL == optionalFieldNode) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Couldn't find optional Field Node in ConditionType. StatusCode %s",
                       UA_StatusCode_name(UA_STATUSCODE_BADNOTFOUND));
        UA_BrowsePathResult_clear(&bpr);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    switch(optionalFieldNode->head.nodeClass) {
        case UA_NODECLASS_VARIABLE: {
            UA_StatusCode retval =
                addOptionalVariableField(server, &condition, &fieldName,
                                         (const UA_VariableNode *)optionalFieldNode, outOptionalNode);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "Adding Condition Optional Variable Field failed. StatusCode %s",
                             UA_StatusCode_name(retval));
            }
            UA_BrowsePathResult_clear(&bpr);
            UA_NODESTORE_RELEASE(server, optionalFieldNode);
            return retval;
        }
        case UA_NODECLASS_OBJECT:{
          UA_StatusCode retval =
              addOptionalObjectField(server, &condition, &fieldName,
                                     (const UA_ObjectNode *)optionalFieldNode, outOptionalNode);
          if(retval != UA_STATUSCODE_GOOD) {
              UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Adding Condition Optional Object Field failed. StatusCode %s",
                           UA_StatusCode_name(retval));
          }
          UA_BrowsePathResult_clear(&bpr);
          UA_NODESTORE_RELEASE(server, optionalFieldNode);
          return retval;
        }
        case UA_NODECLASS_METHOD:
            /*TODO method: Check first logic of creating methods at all (should
              we create a new method or just reference it from the
              ConditionType?)*/
            UA_BrowsePathResult_clear(&bpr);
            UA_NODESTORE_RELEASE(server, optionalFieldNode);
            return UA_STATUSCODE_BADNOTSUPPORTED;
        default:
            UA_BrowsePathResult_clear(&bpr);
            UA_NODESTORE_RELEASE(server, optionalFieldNode);
            return UA_STATUSCODE_BADNOTSUPPORTED;
    }

#else
    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Adding Condition Optional Fields disabled. StatusCode %s",
                 UA_StatusCode_name(UA_STATUSCODE_BADNOTSUPPORTED));
    return UA_STATUSCODE_BADNOTSUPPORTED;
#endif /* CONDITIONOPTIONALFIELDS_SUPPORT */
}

/**
 * add an optional condition field using its name. (Adding optional methods
 * is not implemented yet)
 */
UA_StatusCode
UA_Server_addConditionOptionalField(UA_Server *server, const UA_NodeId condition,
                                    const UA_NodeId conditionType, const UA_QualifiedName fieldName,
                                    UA_NodeId *outOptionalNode) {
    lockServer(server);
    UA_StatusCode res = addConditionOptionalField(server, condition, conditionType,
                                                  fieldName, outOptionalNode);
    unlockServer(server);
    return res;
}

/* Set the value of condition field (only scalar). */
static UA_StatusCode
setConditionField(UA_Server *server, const UA_NodeId condition,
                  const UA_Variant* value, const UA_QualifiedName fieldName) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(value->arrayLength != 0 || value->data <= UA_EMPTY_ARRAY_SENTINEL) {
      //TODO implement logic for array variants!
      CONDITION_ASSERT_RETURN_RETVAL(UA_STATUSCODE_BADNOTIMPLEMENTED,
                                     "Set Condition Field with Array value not implemented",);
    }

    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, condition, 1, &fieldName);
    if(bpr.statusCode != UA_STATUSCODE_GOOD)
        return bpr.statusCode;

    UA_StatusCode retval = writeValueAttribute(server, bpr.targets[0].targetId.nodeId, value);
    UA_BrowsePathResult_clear(&bpr);

    return retval;
}

/* Set the value of condition field (only scalar). */
UA_StatusCode
UA_Server_setConditionField(UA_Server *server, const UA_NodeId condition,
                            const UA_Variant* value, const UA_QualifiedName fieldName) {
    lockServer(server);
    UA_StatusCode retval = setConditionField(server, condition, value, fieldName);
    unlockServer(server);
    return retval;
}

static UA_StatusCode
setConditionVariableFieldProperty(UA_Server *server, const UA_NodeId condition,
                                  const UA_Variant* value,
                                  const UA_QualifiedName variableFieldName,
                                  const UA_QualifiedName variablePropertyName) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(value->arrayLength != 0 || value->data <= UA_EMPTY_ARRAY_SENTINEL) {
        //TODO implement logic for array variants!
        CONDITION_ASSERT_RETURN_RETVAL(UA_STATUSCODE_BADNOTIMPLEMENTED,
                                       "Set Property of Condition Field with Array value not implemented",);
    }

    /* 1) find Variable Field of the Condition*/
    UA_BrowsePathResult bprConditionVariableField =
        browseSimplifiedBrowsePath(server, condition, 1, &variableFieldName);
    if(bprConditionVariableField.statusCode != UA_STATUSCODE_GOOD)
        return bprConditionVariableField.statusCode;

    /* 2) find Property of the Variable Field of the Condition*/
    UA_BrowsePathResult bprVariableFieldProperty =
        browseSimplifiedBrowsePath(server, bprConditionVariableField.targets->targetId.nodeId,
                                   1, &variablePropertyName);
    if(bprVariableFieldProperty.statusCode != UA_STATUSCODE_GOOD) {
        UA_BrowsePathResult_clear(&bprConditionVariableField);
        return bprVariableFieldProperty.statusCode;
    }

    UA_StatusCode retval =
        writeValueAttribute(server, bprVariableFieldProperty.targets[0].targetId.nodeId, value);
    UA_BrowsePathResult_clear(&bprConditionVariableField);
    UA_BrowsePathResult_clear(&bprVariableFieldProperty);
    return retval;
}

/* Set the value of property of condition field. */
UA_StatusCode
UA_Server_setConditionVariableFieldProperty(UA_Server *server, const UA_NodeId condition,
                                            const UA_Variant* value,
                                            const UA_QualifiedName variableFieldName,
                                            const UA_QualifiedName variablePropertyName) {
    lockServer(server);
    UA_StatusCode res = setConditionVariableFieldProperty(server, condition, value,
                                                          variableFieldName, variablePropertyName);
    unlockServer(server);
    return res;
}

/* triggers an event only for an enabled condition. The condition list is
 * updated then with the last generated EventId. */
static UA_StatusCode
triggerConditionEvent(UA_Server *server, const UA_NodeId condition,
                      const UA_NodeId conditionSource, UA_ByteString *outEventId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check if enabled */
    UA_ByteString eventId = UA_BYTESTRING_NULL;
    UA_QualifiedName enabledStateField = UA_QUALIFIEDNAME(0, CONDITION_FIELD_ENABLEDSTATE);
    if(!isTwoStateVariableInTrueState(server, &condition, &enabledStateField)) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Cannot trigger condition event when "
                       CONDITION_FIELD_ENABLEDSTATE"."
                       CONDITION_FIELD_TWOSTATEVARIABLE_ID" is false.");
        return UA_STATUSCODE_BADCONDITIONALREADYDISABLED;
    }

    setIsCallerAC(server, &condition, &conditionSource, true);

    UA_EventDescription ed = {0};
    ed.sourceNode = conditionSource;
    ed.eventInstance = &condition;

    /* Trigger the event for Condition*/
    //Condition Nodes should not be deleted after triggering the event
    UA_StatusCode retval = createEvent(server, &ed, &eventId);
    CONDITION_ASSERT_RETURN_RETVAL(retval, "Triggering condition event failed",);

    setIsCallerAC(server, &condition, &conditionSource, false);

    /* Update list */
    retval = updateConditionLastEventId(server, &condition, &conditionSource, &eventId);
    if(outEventId)
        *outEventId = eventId;
    else
        UA_ByteString_clear(&eventId);
    return retval;
}

/* triggers an event only for an enabled condition. The condition list is
 * updated then with the last generated EventId. */
UA_StatusCode
UA_Server_triggerConditionEvent(UA_Server *server, const UA_NodeId condition,
                                const UA_NodeId conditionSource, UA_ByteString *outEventId) {
    lockServer(server);
    UA_StatusCode res = triggerConditionEvent(server, condition, conditionSource, outEventId);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_deleteCondition(UA_Server *server, const UA_NodeId condition,
                          const UA_NodeId conditionSource) {
    /* Get ConditionSource Entry */
    UA_Boolean found = false; /* Delete from internal list */
    UA_ConditionSource *source, *tmp_source;

    lockServer(server);
    LIST_FOREACH_SAFE(source, &server->conditionSources, listEntry, tmp_source) {
        if(!UA_NodeId_equal(&source->conditionSourceId, &conditionSource))
            continue;

        /* Get Condition Entry */
        UA_Condition *cond, *tmp_cond;
        LIST_FOREACH_SAFE(cond, &source->conditions, listEntry, tmp_cond) {
            if(!UA_NodeId_equal(&cond->conditionId, &condition))
                continue;
            deleteCondition(cond);
            found = true;
            break;
        }

        if(LIST_EMPTY(&source->conditions)){
            UA_NodeId_clear(&source->conditionSourceId);
            LIST_REMOVE(source, listEntry);
            UA_free(source);
        }
        break;
    }
    unlockServer(server);

    if(!found)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Delete from address space */
    return UA_Server_deleteNode(server, condition, true);
}

static UA_StatusCode
getLowLimit(UA_Server *server, UA_NodeId conditionId, UA_Double *lowLimit) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Variant value;
    UA_Variant_init(&value);
    UA_StatusCode retval =
        readObjectProperty(server, conditionId,
                           UA_QUALIFIEDNAME(0, CONDITION_FIELD_LOWLIMIT), &value);
    if(retval == UA_STATUSCODE_GOOD)
        *lowLimit = *(UA_Double*)value.data;
    UA_Variant_clear(&value);
    return retval;
}

static UA_StatusCode
getLowLowLimit(UA_Server *server, UA_NodeId conditionId, UA_Double *lowLowLimit) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Variant value;
    UA_Variant_init(&value);
    UA_StatusCode retval =
        readObjectProperty(server, conditionId,
                           UA_QUALIFIEDNAME(0, CONDITION_FIELD_LOWLOWLIMIT), &value);
    if(retval == UA_STATUSCODE_GOOD)
        *lowLowLimit = *(UA_Double*)value.data;
    UA_Variant_clear(&value);
    return retval;
}

static UA_StatusCode
getHighLimit(UA_Server *server, UA_NodeId conditionId, UA_Double *highLimit) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Variant value;
    UA_Variant_init(&value);
    UA_StatusCode retval =
        readObjectProperty(server, conditionId,
                           UA_QUALIFIEDNAME(0, CONDITION_FIELD_HIGHLIMIT), &value);
    if(retval == UA_STATUSCODE_GOOD)
        *highLimit = *(UA_Double*)value.data;
    UA_Variant_clear(&value);
    return retval;
}

static UA_StatusCode
getHighHighLimit(UA_Server *server, UA_NodeId conditionId, UA_Double *highHighLimit) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Variant value;
    UA_Variant_init(&value);
    UA_StatusCode retval =
        readObjectProperty(server, conditionId,
                           UA_QUALIFIEDNAME(0, CONDITION_FIELD_HIGHHIGHLIMIT), &value);
    if(retval == UA_STATUSCODE_GOOD)
        *highHighLimit = *(UA_Double*)value.data;
    UA_Variant_clear(&value);
    return retval;
}

static UA_StatusCode
setLimitState(UA_Server *server, const UA_NodeId conditionId,
              UA_Double limitValue) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId limitState = UA_NODEID_NULL;
    UA_Double lowLowLimit;
    UA_Double lowLimit;
    UA_Double highLimit;
    UA_Double highHighLimit;
    UA_Variant value;
    UA_QualifiedName currentStateField = UA_QUALIFIEDNAME(0,"CurrentState");
    UA_QualifiedName currentStateIdField = UA_QUALIFIEDNAME(0,"Id");
    UA_StatusCode retval = getConditionFieldNodeId(server, &conditionId,
                                                   &fieldLimitStateQN, &limitState);

    retval |= getHighHighLimit(server, conditionId, &highHighLimit);
    if(retval == UA_STATUSCODE_GOOD) {
        if(limitValue >= highHighLimit) {
            UA_NodeId highHighLimitId = UA_NODEID_NULL;
            retval |= getConditionFieldNodeId(server, &conditionId,
                                              &fieldHighHighLimitQN, &highHighLimitId);
            UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, ACTIVE_HIGHHIGH_TEXT);
            UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
            retval |= setConditionField(server, limitState, &value, currentStateField);
            UA_Variant_setScalar(&value, &highHighLimitId, &UA_TYPES[UA_TYPES_NODEID]);
            retval |= setConditionVariableFieldProperty(server, limitState, &value,
                                                        currentStateField, currentStateIdField);
            return retval;
        }
    }

    retval |= getHighLimit(server, conditionId, &highLimit);
    if(retval == UA_STATUSCODE_GOOD) {
        if(limitValue >= highLimit) {
            UA_NodeId highLimitId = UA_NODEID_NULL;
            retval |= getConditionFieldNodeId(server, &conditionId, &fieldHighLimitQN, &highLimitId);
            UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, ACTIVE_HIGH_TEXT);
            UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
            retval |= setConditionField(server, limitState, &value, currentStateField);

            UA_Variant_setScalar(&value, &highLimitId, &UA_TYPES[UA_TYPES_NODEID]);
            retval |= setConditionVariableFieldProperty(server, limitState, &value,
                                                        currentStateField,
                                                        currentStateIdField);
            return retval;
        }
    }

    retval |= getLowLowLimit(server, conditionId, &lowLowLimit);
    if(retval == UA_STATUSCODE_GOOD) {
        if(limitValue <= lowLowLimit) {
            UA_NodeId lowLowLimitId = UA_NODEID_NULL;
            retval |= getConditionFieldNodeId(server, &conditionId,
                                              &fieldLowLowLimitQN, &lowLowLimitId);
            UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, ACTIVE_LOWLOW_TEXT);
            UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
            retval |= setConditionField(server, limitState, &value, currentStateField);
            UA_Variant_setScalar(&value, &lowLowLimitId, &UA_TYPES[UA_TYPES_NODEID]);
            retval |= setConditionVariableFieldProperty(server, limitState, &value,
                                                        currentStateField,
                                                        currentStateIdField);
            return retval;
        }
    }

    retval |= getLowLimit(server, conditionId, &lowLimit);
    if(retval == UA_STATUSCODE_GOOD) {
        if(limitValue <= lowLimit) {
            UA_NodeId lowLimitId = UA_NODEID_NULL;
            retval |= getConditionFieldNodeId(server, &conditionId, &fieldLowLimitQN, &lowLimitId);
            UA_LocalizedText text = UA_LOCALIZEDTEXT(LOCALE, ACTIVE_LOW_TEXT);
            UA_Variant_setScalar(&value, &text, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
            retval |= setConditionField(server, limitState, &value, currentStateField);
            UA_Variant_setScalar(&value, &lowLimitId, &UA_TYPES[UA_TYPES_NODEID]);
            retval |= setConditionVariableFieldProperty(server, limitState, &value,
                                                        currentStateField,
                                                        currentStateIdField);
            return retval;
        }
    }

    UA_LocalizedText textNull = UA_LOCALIZEDTEXT(LOCALE_NULL, TEXT_NULL);
    UA_Variant_setScalar(&value, &textNull, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
    retval |= setConditionField(server, limitState, &value, currentStateField);

    UA_NodeId nodeIdNull = UA_NODEID_NULL;
    UA_Variant_setScalar(&value, &nodeIdNull, &UA_TYPES[UA_TYPES_NODEID]);
    retval |= setConditionVariableFieldProperty(server, limitState, &value,
                                                currentStateField,
                                                currentStateIdField);
    return retval;
}

UA_StatusCode
UA_Server_setLimitState(UA_Server *server, const UA_NodeId conditionId,
                        UA_Double limitValue) {
    lockServer(server);
    UA_StatusCode res = setLimitState(server, conditionId, limitValue);
    unlockServer(server);
    return res;
}

/* Currently supports only MBEDTLS and OpenSSL */
UA_StatusCode
UA_Server_setExpirationDate(UA_Server *server, const UA_NodeId conditionId,
                            UA_ByteString  cert) {
    UA_StatusCode retval;
    if(cert.data == NULL){
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "No Certificate found.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_CertificateGroup *cv = &server->config.sessionPKI;
    UA_DateTime getExpiryDateAndTime = 0;
    if(cv == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Certificate verification is not registered");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    retval = UA_CertificateUtils_getExpirationDate(&cert, &getExpiryDateAndTime);
    if(retval != UA_STATUSCODE_GOOD || getExpiryDateAndTime == 0){
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Failed to get certificate expiration date");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Write the expiry date to the propery of the condition instance */
    retval = UA_Server_writeObjectProperty_scalar(server, conditionId,
                                                  fieldExpirationDateQN,
                                                  &getExpiryDateAndTime,
                                                  &UA_TYPES[UA_TYPES_DATETIME]);
    return retval;
}
#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */

/**** amalgamated original file "/src/server/ua_services.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014-2015, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Joakim L. Gilje
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2023 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Phuong Nguyen)
 */

/* This file contains the service invocation logic that is called from all
 * communication backends */


#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
/* store the authentication token and session ID so we can help fuzzing by
 * setting these values in the next request automatically */
UA_NodeId unsafe_fuzz_authenticationToken = {0, UA_NODEIDTYPE_NUMERIC, {0}};
#endif

/* The counterOffset is the offset of the UA_ServiceCounterDataType for the
 * service in the UA_ SessionDiagnosticsDataType. */
#ifdef UA_ENABLE_DIAGNOSTICS
# define UA_SERVICECOUNTER_OFFSET_NONE(requiresSession) 0, requiresSession
# define UA_SERVICECOUNTER_OFFSET(X, requiresSession) \
    offsetof(UA_SessionDiagnosticsDataType, X), requiresSession
#else
# define UA_SERVICECOUNTER_OFFSET_NONE(requiresSession) requiresSession
# define UA_SERVICECOUNTER_OFFSET(X, requiresSession) requiresSession
#endif

static UA_ServiceDescription serviceDescriptions[] = {
    {UA_NS0ID_GETENDPOINTSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_GetEndpoints,
     &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]},
    {UA_NS0ID_FINDSERVERSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_FindServers,
     &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST], &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]},
#ifdef UA_ENABLE_DISCOVERY
    {UA_NS0ID_REGISTERSERVERREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_RegisterServer,
     &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST], &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE]},
    {UA_NS0ID_REGISTERSERVER2REQUEST_ENCODING_DEFAULTBINARY,
    UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_RegisterServer2,
    &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST], &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE]},
# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    {UA_NS0ID_FINDSERVERSONNETWORKREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_FindServersOnNetwork,
     &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST], &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]},
# endif
#endif
    {UA_NS0ID_CREATESESSIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)(uintptr_t)Service_CreateSession,
     &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST], &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]},
    {UA_NS0ID_ACTIVATESESSIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)(uintptr_t)Service_ActivateSession,
     &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],  &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]},
    {UA_NS0ID_CLOSESESSIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(true), (UA_Service)(uintptr_t)Service_CloseSession,
     &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST], &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]},
    {UA_NS0ID_CANCELREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(true), (UA_Service)Service_Cancel,
     &UA_TYPES[UA_TYPES_CANCELREQUEST], &UA_TYPES[UA_TYPES_CANCELRESPONSE]},
    {UA_NS0ID_READREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(readCount, true), (UA_Service)Service_Read,
     &UA_TYPES[UA_TYPES_READREQUEST], &UA_TYPES[UA_TYPES_READRESPONSE]},
    {UA_NS0ID_WRITEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(writeCount, true), (UA_Service)Service_Write,
     &UA_TYPES[UA_TYPES_WRITEREQUEST], &UA_TYPES[UA_TYPES_WRITERESPONSE]},
    {UA_NS0ID_BROWSEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(browseCount, true), (UA_Service)Service_Browse,
     &UA_TYPES[UA_TYPES_BROWSEREQUEST], &UA_TYPES[UA_TYPES_BROWSERESPONSE]},
    {UA_NS0ID_BROWSENEXTREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(browseNextCount, true), (UA_Service)Service_BrowseNext,
     &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]},
    {UA_NS0ID_REGISTERNODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(registerNodesCount, true), (UA_Service)Service_RegisterNodes,
     &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST], &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]},
    {UA_NS0ID_UNREGISTERNODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(unregisterNodesCount, true), (UA_Service)Service_UnregisterNodes,
     &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST], &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]},
    {UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(translateBrowsePathsToNodeIdsCount, true), (UA_Service)Service_TranslateBrowsePathsToNodeIds,
     &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST], &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]},
#ifdef UA_ENABLE_SUBSCRIPTIONS
    {UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(createSubscriptionCount, true), (UA_Service)Service_CreateSubscription,
     &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]},
    {UA_NS0ID_PUBLISHREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(publishCount, true), (UA_Service)Service_Publish,
     &UA_TYPES[UA_TYPES_PUBLISHREQUEST], &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]},
    {UA_NS0ID_REPUBLISHREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(republishCount, true), (UA_Service)Service_Republish,
     &UA_TYPES[UA_TYPES_REPUBLISHREQUEST], &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE]},
    {UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(modifySubscriptionCount, true), (UA_Service)Service_ModifySubscription,
     &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST], &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]},
    {UA_NS0ID_SETPUBLISHINGMODEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(setPublishingModeCount, true), (UA_Service)Service_SetPublishingMode,
     &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST], &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]},
    {UA_NS0ID_DELETESUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteSubscriptionsCount, true), (UA_Service)Service_DeleteSubscriptions,
     &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]},
    {UA_NS0ID_TRANSFERSUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(transferSubscriptionsCount, true), (UA_Service)Service_TransferSubscriptions,
     &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSREQUEST], &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSRESPONSE]},
    {UA_NS0ID_CREATEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(createMonitoredItemsCount, true), (UA_Service)Service_CreateMonitoredItems,
     &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]},
    {UA_NS0ID_DELETEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteMonitoredItemsCount, true), (UA_Service)Service_DeleteMonitoredItems,
     &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST], &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]},
    {UA_NS0ID_MODIFYMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(modifyMonitoredItemsCount, true), (UA_Service)Service_ModifyMonitoredItems,
     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]},
    {UA_NS0ID_SETMONITORINGMODEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(setMonitoringModeCount, true), (UA_Service)Service_SetMonitoringMode,
     &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]},
    {UA_NS0ID_SETTRIGGERINGREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(setTriggeringCount, true), (UA_Service)Service_SetTriggering,
     &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]},
#endif
#ifdef UA_ENABLE_HISTORIZING
    {UA_NS0ID_HISTORYREADREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(historyReadCount, true), (UA_Service)Service_HistoryRead,
     &UA_TYPES[UA_TYPES_HISTORYREADREQUEST], &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]},
    {UA_NS0ID_HISTORYUPDATEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(historyUpdateCount, true), (UA_Service)Service_HistoryUpdate,
     &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST], &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]},
#endif
#ifdef UA_ENABLE_METHODCALLS
    {UA_NS0ID_CALLREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(callCount, true), (UA_Service)Service_Call,
     &UA_TYPES[UA_TYPES_CALLREQUEST], &UA_TYPES[UA_TYPES_CALLRESPONSE]},
#endif
#ifdef UA_ENABLE_NODEMANAGEMENT
    {UA_NS0ID_ADDNODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(addNodesCount, true), (UA_Service)Service_AddNodes,
     &UA_TYPES[UA_TYPES_ADDNODESREQUEST], &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]},
    {UA_NS0ID_ADDREFERENCESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(addReferencesCount, true), (UA_Service)Service_AddReferences,
     &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST], &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]},
    {UA_NS0ID_DELETENODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteNodesCount, true), (UA_Service)Service_DeleteNodes,
     &UA_TYPES[UA_TYPES_DELETENODESREQUEST], &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]},
    {UA_NS0ID_DELETEREFERENCESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteReferencesCount, true), (UA_Service)Service_DeleteReferences,
     &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST], &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]},
#endif
    {0, UA_SERVICECOUNTER_OFFSET_NONE(false), NULL, NULL, NULL}
};

UA_ServiceDescription *
getServiceDescription(UA_UInt32 requestTypeId) {
    for(size_t i = 0; serviceDescriptions[i].requestTypeId > 0; i++) {
        if(serviceDescriptions[i].requestTypeId == requestTypeId)
            return &serviceDescriptions[i];
    }
    return NULL;
}

/* Allocates the results array and iterates over it to execute the operations
 * within a request */
UA_StatusCode
allocProcessServiceOperations(UA_Server *server, UA_Session *session,
                              UA_ServiceOperation operationCallback,
                              const void *context, const size_t *requestOperations,
                              const UA_DataType *requestOperationsType,
                              size_t *responseOperations,
                              const UA_DataType *responseOperationsType) {
    size_t ops = *requestOperations;
    if(ops == 0)
        return UA_STATUSCODE_BADNOTHINGTODO;

    /* No padding after size_t */
    void **respPos = (void**)((uintptr_t)responseOperations + sizeof(size_t));
    *respPos = UA_Array_new(ops, responseOperationsType);
    if(!(*respPos))
        return UA_STATUSCODE_BADOUTOFMEMORY;

    *responseOperations = ops;
    uintptr_t respOp = (uintptr_t)*respPos;
    /* No padding after size_t */
    uintptr_t reqOp = *(uintptr_t*)((uintptr_t)requestOperations + sizeof(size_t));
    for(size_t i = 0; i < ops; i++) {
        operationCallback(server, session, context, (void*)reqOp, (void*)respOp);
        reqOp += requestOperationsType->memSize;
        respOp += responseOperationsType->memSize;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_Boolean
processServiceInternal(UA_Server *server, UA_SecureChannel *channel, UA_Session *session,
                       UA_UInt32 requestId, UA_ServiceDescription *sd,
                       const UA_Request *request, UA_Response *response) {
    UA_ResponseHeader *rh = &response->responseHeader;

    /* Check timestamp in the request header */
    if(request->requestHeader.timestamp == 0 &&
       server->config.verifyRequestTimestamp <= UA_RULEHANDLING_WARN) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "The server sends no timestamp in the request header. "
                               "See the 'verifyRequestTimestamp' setting.");
        if(server->config.verifyRequestTimestamp <= UA_RULEHANDLING_ABORT) {
            rh->serviceResult = UA_STATUSCODE_BADINVALIDTIMESTAMP;
            return true;
        }
    }

    /* If it is an unencrypted (#None) channel, only allow the discovery services */
    if(server->config.securityPolicyNoneDiscoveryOnly &&
       channel->securityPolicy->policyType == UA_SECURITYPOLICYTYPE_NONE &&
       sd->requestType != &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST] &&
       sd->requestType != &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST]
#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
       && sd->requestType != &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST]
#endif
       ) {
        rh->serviceResult = UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
        return true;
    }

    /* Session lifecycle services */
    if(sd->requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST] ||
       sd->requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST] ||
       sd->requestType == &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST]) {
        UA_ChannelService cs = (UA_ChannelService)(uintptr_t)sd->serviceCallback;
        cs(server, channel, request, response);
        /* Store the authentication token created during CreateSession to help
         * fuzzing cover more lines */
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
        if(sd->requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]) {
            UA_CreateSessionResponse *res = &response->createSessionResponse;
            UA_NodeId_clear(&unsafe_fuzz_authenticationToken);
            UA_NodeId_copy(&res->authenticationToken, &unsafe_fuzz_authenticationToken);
        }
#endif
        return true;
    }

    /* Set an anonymous, inactive session for services that need no session */
    UA_Session anonymousSession;
    if(!session) {
        UA_assert(!sd->sessionRequired);
        UA_Session_init(&anonymousSession);
        anonymousSession.sessionId = UA_NODEID_GUID(0, UA_GUID_NULL);
        anonymousSession.channel = channel;
        session = &anonymousSession;
    }

    /* Trying to use a non-activated session? */
    if(sd->sessionRequired && !session->activated) {
        UA_assert(session != &anonymousSession); /* because sd->sessionRequired */
#ifdef UA_ENABLE_TYPEDESCRIPTION
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "%s refused on a non-activated session",
                               sd->requestType->typeName);
#else
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Service %" PRIu32 " refused on a non-activated session",
                               sd->requestType->binaryEncodingId.identifier.numeric);
#endif
        UA_Session_remove(server, session, UA_SHUTDOWNREASON_ABORT);
        rh->serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED;
        return true;
    }

    /* Update the session lifetime */
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_DateTime now = el->dateTime_now(el);
    UA_Session_updateLifetime(session, now, nowMonotonic);

    /* Store the request id -- will be used to create async responses */
    server->asyncManager.currentRequestId = requestId;
    server->asyncManager.currentRequestHandle = request->requestHeader.requestHandle;

    /* Execute the service */
    return sd->serviceCallback(server, session, request, response);
}

UA_Boolean
processRequest(UA_Server *server, UA_SecureChannel *channel,
               UA_UInt32 requestId, UA_ServiceDescription *sd,
               const UA_Request *request, UA_Response *response) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Set the authenticationToken from the create session request to help
     * fuzzing cover more lines */
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    UA_NodeId *authenticationToken = (UA_NodeId *)(uintptr_t)
        &request->requestHeader.authenticationToken;
    if(!UA_NodeId_isNull(authenticationToken) &&
       !UA_NodeId_isNull(&unsafe_fuzz_authenticationToken)) {
        UA_NodeId_clear(authenticationToken);
        UA_NodeId_copy(&unsafe_fuzz_authenticationToken, authenticationToken);
    }
#endif

    /* Get the session bound to the SecureChannel (not necessarily activated) */
    UA_Session *session = NULL;
    response->responseHeader.serviceResult =
        getBoundSession(server, channel, &request->requestHeader.authenticationToken, &session);
    if(!session && sd->sessionRequired)
        return true;

    /* The session can be NULL if not required */
    response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
    UA_NodeId sessionId = (session) ? session->sessionId : UA_NODEID_NULL;

    /* Notify with UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_BEGIN */
    UA_ServerConfig *config = &server->config;
    static UA_THREAD_LOCAL UA_KeyValuePair notifyPayload[4] = {
        {{0, UA_STRING_STATIC("securechannel-id")}, {0}},
        {{0, UA_STRING_STATIC("session-id")}, {0}},
        {{0, UA_STRING_STATIC("request-id")}, {0}},
        {{0, UA_STRING_STATIC("service-type")}, {0}}
    };
    UA_KeyValueMap notifyPayloadMap = {4, notifyPayload};
    if(config->globalNotificationCallback || config->serviceNotificationCallback) {
        UA_Variant_setScalar(&notifyPayload[0].value, &channel->securityToken.channelId,
                             &UA_TYPES[UA_TYPES_UINT32]);
        UA_Variant_setScalar(&notifyPayload[1].value, &sessionId,
                             &UA_TYPES[UA_TYPES_NODEID]);
        UA_Variant_setScalar(&notifyPayload[2].value, &requestId,
                             &UA_TYPES[UA_TYPES_UINT32]);
        UA_Variant_setScalar(&notifyPayload[3].value,
                             (void *)(uintptr_t)&sd->requestType->typeId,
                             &UA_TYPES[UA_TYPES_NODEID]);
    }
    UA_ApplicationNotificationType nt = UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_BEGIN;
    if(config->serviceNotificationCallback)
        config->serviceNotificationCallback(server, nt, notifyPayloadMap);
    if(config->globalNotificationCallback)
        config->globalNotificationCallback(server, nt, notifyPayloadMap);

    /* Process the service */
    UA_Boolean done = processServiceInternal(server, channel, session,
                                             requestId, sd, request, response);

    /* Notify with UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_END if the service was
     * completed synchronously. For async completion of a service, this gets
     * called eventually in ua_server_async.c. */
    nt = (done) ? UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_END :
        UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_ASYNC;
    if(config->serviceNotificationCallback)
        config->serviceNotificationCallback(server, nt, notifyPayloadMap);
    if(config->globalNotificationCallback)
        config->globalNotificationCallback(server, nt, notifyPayloadMap);

    /* Update the service statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    if(session) {
        session->diagnostics.totalRequestCount.totalCount++;
        if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
            session->diagnostics.totalRequestCount.errorCount++;
        if(sd->counterOffset != 0) {
            UA_ServiceCounterDataType *serviceCounter = (UA_ServiceCounterDataType*)
                (((uintptr_t)&session->diagnostics) + sd->counterOffset);
            serviceCounter->totalCount++;
            if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
                serviceCounter->errorCount++;
        }
    }
#endif

    return done;
}

/**** amalgamated original file "/src/server/ua_services_view.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Ecosmos
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) pschoppe
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Henrik Norrman
 */


#define UA_MAX_TREE_RECURSE 50 /* How deep up/down the tree do we recurse at most? */

static UA_UInt32
resultMask2AttributesMask(UA_UInt32 resultMask) {
    UA_UInt32 result = 0;
    if(resultMask & UA_BROWSERESULTMASK_NODECLASS)
        result |= UA_NODEATTRIBUTESMASK_NODECLASS;
    if(resultMask & UA_BROWSERESULTMASK_BROWSENAME)
        result |= UA_NODEATTRIBUTESMASK_BROWSENAME;
    if(resultMask & UA_BROWSERESULTMASK_DISPLAYNAME)
        result |= UA_NODEATTRIBUTESMASK_DISPLAYNAME;
    return result;
}

UA_StatusCode
referenceTypeIndices(UA_Server *server, const UA_NodeId *refType,
                     UA_ReferenceTypeSet *indices, UA_Boolean includeSubtypes) {
    if(UA_NodeId_isNull(refType)) {
        *indices = UA_REFERENCETYPESET_ALL;
        return UA_STATUSCODE_GOOD;
    }

    UA_ReferenceTypeSet_init(indices);

    /* Get the node with only the NodeClass attribute. If it is a
     * ReferenceTypeNode, then the indices are always included, as this is an
     * open62541 specific field (not selectable via the attribute id). */
    const UA_Node *refNode =
        UA_NODESTORE_GET_SELECTIVE(server, refType,
                                   UA_NODEATTRIBUTESMASK_NODECLASS,
                                   UA_REFERENCETYPESET_NONE,
                                   UA_BROWSEDIRECTION_INVALID);

    if(!refNode)
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;

    if(refNode->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        UA_NODESTORE_RELEASE(server, refNode);
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    if(!includeSubtypes)
        *indices = UA_REFTYPESET(refNode->referenceTypeNode.referenceTypeIndex);
    else
        *indices = refNode->referenceTypeNode.subTypes;

    UA_NODESTORE_RELEASE(server, refNode);
    return UA_STATUSCODE_GOOD;
}

static UA_Boolean
matchClassMask(const UA_Node *node, UA_UInt32 nodeClassMask) {
    if(nodeClassMask != UA_NODECLASS_UNSPECIFIED &&
       (node->head.nodeClass & nodeClassMask) == 0)
        return false;
    return true;
}

/****************/
/* IsNodeInTree */
/****************/

/* Internal method to check if a node is already upwards from a leaf node */

static enum ZIP_CMP
cmpRefTarget(const void *a, const void *b) {
    const UA_ReferenceTarget *aa = (const UA_ReferenceTarget*)a;
    const UA_ReferenceTarget *bb = (const UA_ReferenceTarget*)b;
    return (enum ZIP_CMP)UA_NodePointer_order(aa->targetId, bb->targetId);
}

typedef ZIP_HEAD(UA_ParentRefsTree, UA_ReferenceTargetTreeElem) UA_ParentRefsTree;
ZIP_FUNCTIONS(UA_ParentRefsTree, UA_ReferenceTargetTreeElem, idTreeEntry,
              UA_NodePointer, target, cmpRefTarget)

struct IsNodeInTreeContext {
    UA_Server *server;
    UA_NodePointer nodeToFind;
    UA_ParentRefsTree parents;
    UA_ReferenceTypeSet relevantRefs;
    UA_UInt16 depth;
};

static void *
isNodeInTreeIterateCallback(void *context, UA_ReferenceTarget *t) {
    struct IsNodeInTreeContext *tc =
        (struct IsNodeInTreeContext*)context;

    /* Don't follow remote targets */
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;

    /* Found the node? -> return non-NULL */
    if(UA_NodePointer_equal(tc->nodeToFind, t->targetId))
        return (void*)0x01;

    /* Prevent endless loop */
    if(ZIP_FIND(UA_ParentRefsTree, &tc->parents, &t->targetId))
        return NULL;

    /* Prevent pathological recursion depth */
    if(tc->depth >= UA_MAX_TREE_RECURSE)
        return NULL;

    /* Get the node without attributes (if the NodeStore supports it) and only
     * the relevant references in inverse direction */
    const UA_Node *node =
        UA_NODESTORE_GETFROMREF_SELECTIVE(tc->server, t->targetId,
                                          UA_NODEATTRIBUTESMASK_NONE,
                                          tc->relevantRefs,
                                          UA_BROWSEDIRECTION_INVERSE);
    if(!node)
        return NULL;

    /* Add current NodeId to parents tree */
    UA_ReferenceTargetTreeElem stackElem;
    stackElem.target = *t;
    ZIP_INSERT(UA_ParentRefsTree, &tc->parents, &stackElem);

    /* Recurse into appropriate references starting from this tree */
    tc->depth++;
    void *res = NULL;
    for(size_t i = 0; i < node->head.referencesSize && !res; i++) {
        UA_NodeReferenceKind *rk = &node->head.references[i];
        /* Search upwards in the tree */
        if(!rk->isInverse)
            continue;

        /* Consider only the indicated reference types */
        if(!UA_ReferenceTypeSet_contains(&tc->relevantRefs, rk->referenceTypeIndex))
            continue;

        res = UA_NodeReferenceKind_iterate(rk, isNodeInTreeIterateCallback, tc);
    }
    tc->depth--;

    /* Clean up */
    UA_NODESTORE_RELEASE(tc->server, node);
    ZIP_REMOVE(UA_ParentRefsTree, &tc->parents, &stackElem);
    return res;
}

UA_Boolean
isNodeInTree(UA_Server *server, const UA_NodeId *leafNode,
             const UA_NodeId *nodeToFind,
             const UA_ReferenceTypeSet *relevantRefs) {
    struct IsNodeInTreeContext ctx;
    memset(&ctx, 0, sizeof(struct IsNodeInTreeContext));
    ctx.server = server;
    ctx.nodeToFind = UA_NodePointer_fromNodeId(nodeToFind);
    ctx.relevantRefs = *relevantRefs;
    UA_ReferenceTarget tmpTarget;
    memset(&tmpTarget, 0, sizeof(UA_ReferenceTarget));
    tmpTarget.targetId = UA_NodePointer_fromNodeId(leafNode);
    return (isNodeInTreeIterateCallback(&ctx, &tmpTarget) != NULL);
}

UA_Boolean
isNodeInTree_singleRef(UA_Server *server, const UA_NodeId *leafNode,
                       const UA_NodeId *nodeToFind, const UA_Byte relevantRefTypeIndex) {
    UA_ReferenceTypeSet reftypes = UA_REFTYPESET(relevantRefTypeIndex);
    return isNodeInTree(server, leafNode, nodeToFind, &reftypes);
}

static enum ZIP_CMP
cmpTarget(const void *a, const void *b) {
    const RefEntry *aa = (const RefEntry*)a;
    const RefEntry *bb = (const RefEntry*)b;
    if(aa->targetHash < bb->targetHash)
        return ZIP_CMP_LESS;
    if(aa->targetHash > bb->targetHash)
        return ZIP_CMP_MORE;
    return (enum ZIP_CMP)UA_ExpandedNodeId_order(aa->target, bb->target);
}

ZIP_FUNCTIONS(RefHead, RefEntry, zipfields, RefEntry, zipfields, cmpTarget)

UA_StatusCode
RefTree_init(RefTree *rt) {
    rt->size = 0;
    rt->capacity = 0;
    ZIP_INIT(&rt->head);
    size_t space = (sizeof(UA_ExpandedNodeId) + sizeof(RefEntry)) * UA_REFTREE_INITIAL_SIZE;
    rt->targets = (UA_ExpandedNodeId*)UA_malloc(space);
    if(!rt->targets)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rt->capacity = UA_REFTREE_INITIAL_SIZE;
    return UA_STATUSCODE_GOOD;
}

void
RefTree_clear(RefTree *rt) {
    for(size_t i = 0; i < rt->size; i++)
        UA_ExpandedNodeId_clear(&rt->targets[i]);
    if(rt->targets)
        UA_free(rt->targets);
}

/* Double the capacity of the reftree */
static UA_StatusCode UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
RefTree_double(RefTree *rt) {
    size_t capacity = rt->capacity * 2;
    UA_assert(capacity > 0);
    size_t space = (sizeof(UA_ExpandedNodeId) + sizeof(RefEntry)) * capacity;
    UA_ExpandedNodeId *newTargets = (UA_ExpandedNodeId*)UA_realloc(rt->targets, space);
    if(!newTargets)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Move the entries to the new location  */
    RefEntry *reArray = (RefEntry*)
        ((uintptr_t)newTargets + (capacity * sizeof(UA_ExpandedNodeId)));
    RefEntry *oldReArray = (RefEntry*)
        ((uintptr_t)newTargets + (rt->capacity * sizeof(UA_ExpandedNodeId)));
    memmove(reArray, oldReArray, rt->size * sizeof(RefEntry));

    /* Reinsert all entries into the tree. The new pointer location has changed
     * their ziptree rank. */
    rt->head.root = NULL;
    for(size_t i = 0; i < rt->size; i++) {
        reArray[i].target = &newTargets[i];
        ZIP_INSERT(RefHead, &rt->head, &reArray[i]);
    }

    rt->capacity = capacity;
    rt->targets = newTargets;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
RefTree_add(RefTree *rt, UA_NodePointer target, UA_Boolean *duplicate) {
    UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(target);

    /* Is the target already in the tree? */
    RefEntry dummy;
    memset(&dummy, 0, sizeof(RefEntry));
    dummy.target = &en;
    dummy.targetHash = UA_ExpandedNodeId_hash(&en);
    if(ZIP_FIND(RefHead, &rt->head, &dummy)) {
        if(duplicate)
            *duplicate = true;
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode s = UA_STATUSCODE_GOOD;
    if(rt->capacity <= rt->size) {
        s = RefTree_double(rt);
        if(s != UA_STATUSCODE_GOOD)
            return s;
    }
    s = UA_ExpandedNodeId_copy(&en, &rt->targets[rt->size]);
    if(s != UA_STATUSCODE_GOOD)
        return s;
    RefEntry *re = (RefEntry*)((uintptr_t)rt->targets +
                               (sizeof(UA_ExpandedNodeId) * rt->capacity) +
                               (sizeof(RefEntry) * rt->size));
    re->target = &rt->targets[rt->size];
    re->targetHash = dummy.targetHash;
    ZIP_INSERT(RefHead, &rt->head, re);
    rt->size++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
RefTree_addNodeId(RefTree *rt, const UA_NodeId *target,
                  UA_Boolean *duplicate) {
    return RefTree_add(rt, UA_NodePointer_fromNodeId(target), duplicate);
}

UA_Boolean
RefTree_contains(RefTree *rt, const UA_ExpandedNodeId *target) {
    RefEntry dummy;
    dummy.target = target;
    dummy.targetHash = UA_ExpandedNodeId_hash(target);
    return !!ZIP_FIND(RefHead, &rt->head, &dummy);
}

UA_Boolean
RefTree_containsNodeId(RefTree *rt, const UA_NodeId *target) {
    UA_ExpandedNodeId en;
    en.nodeId = *target;
    en.namespaceUri = UA_STRING_NULL;
    en.serverIndex = 0;
    return RefTree_contains(rt, &en);
}

/********************/
/* Browse Recursive */
/********************/

struct BrowseRecursiveContext {
    UA_Server *server;
    RefTree *rt;
    UA_UInt16 depth;
    UA_BrowseDirection browseDirection;
    UA_ReferenceTypeSet refTypes;
    UA_UInt32 nodeClassMask;
    UA_StatusCode status;
    UA_Boolean includeStartNodes;
};

static void *
browseRecursiveCallback(void *context, UA_ReferenceTarget *t) {
    struct BrowseRecursiveContext *brc =
        (struct BrowseRecursiveContext*)context;

    /* Have we reached the max recursion depth? */
    if(brc->depth >= UA_MAX_TREE_RECURSE)
        return NULL;

    /* Is this a non-local reference? If yes include it in the returned set. */
    if(!UA_NodePointer_isLocal(t->targetId)) {
        brc->status = RefTree_add(brc->rt, t->targetId, NULL);
        return (brc->status == UA_STATUSCODE_GOOD) ? NULL : (void*)0x01;
    }

    /* We only look at the NodeClass attribute and a subset of the references.
     * Get a node with only these elements if the NodeStore supports that. */
    const UA_Node *node =
        UA_NODESTORE_GETFROMREF_SELECTIVE(brc->server, t->targetId,
                                          UA_NODEATTRIBUTESMASK_NODECLASS,
                                          brc->refTypes, brc->browseDirection);
    if(!node)
        return NULL;

    /* Add the current node if we don't want to skip it as a start node and it
     * matches the nodeClassMask filter. Recurse into the children in any
     * case. */
    void *res = NULL;
    const UA_NodeHead *head = &node->head;
    if((brc->includeStartNodes || brc->depth > 0)  &&
       matchClassMask(node, brc->nodeClassMask)) {
        UA_Boolean duplicate = false;
        brc->status = RefTree_addNodeId(brc->rt, &head->nodeId, &duplicate);
        if(duplicate || brc->status != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Recurse */
    brc->depth++;
    for(size_t i = 0; i < head->referencesSize && !res; i++) {
        UA_NodeReferenceKind *rk = &head->references[i];

        /* Reference in the right direction? */
        if(rk->isInverse && brc->browseDirection == UA_BROWSEDIRECTION_FORWARD)
            continue;
        if(!rk->isInverse && brc->browseDirection == UA_BROWSEDIRECTION_INVERSE)
            continue;

        /* Is the reference part of the hierarchy of references we look for? */
        if(!UA_ReferenceTypeSet_contains(&brc->refTypes, rk->referenceTypeIndex))
            continue;

        res = UA_NodeReferenceKind_iterate(rk, browseRecursiveCallback, brc);
    }
    brc->depth--;

 cleanup:
    UA_NODESTORE_RELEASE(brc->server, node);
    return (brc->status == UA_STATUSCODE_GOOD) ? NULL : (void*)0x01;
}

UA_StatusCode
browseRecursive(UA_Server *server, size_t startNodesSize, const UA_NodeId *startNodes,
                UA_BrowseDirection browseDirection, const UA_ReferenceTypeSet *refTypes,
                UA_UInt32 nodeClassMask, UA_Boolean includeStartNodes,
                size_t *resultsSize, UA_ExpandedNodeId **results) {
    RefTree rt;
    UA_StatusCode retval = RefTree_init(&rt);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    struct BrowseRecursiveContext brc;
    brc.server = server;
    brc.rt = &rt;
    brc.depth = 0;
    brc.refTypes = *refTypes;
    brc.nodeClassMask = nodeClassMask;
    brc.status = UA_STATUSCODE_GOOD;
    brc.includeStartNodes = includeStartNodes;

    for(size_t i = 0; i < startNodesSize && brc.status == UA_STATUSCODE_GOOD; i++) {
        UA_ReferenceTarget target;
        target.targetId = UA_NodePointer_fromNodeId(&startNodes[i]);

        /* Call the inner recursive browse separately for the search direction.
         * Otherwise we might take one step up and another step down in the
         * search tree. */
        if(browseDirection == UA_BROWSEDIRECTION_FORWARD ||
           browseDirection == UA_BROWSEDIRECTION_BOTH) {
            brc.browseDirection = UA_BROWSEDIRECTION_FORWARD;
            browseRecursiveCallback(&brc, &target);
        }

        if(browseDirection == UA_BROWSEDIRECTION_INVERSE ||
           browseDirection == UA_BROWSEDIRECTION_BOTH) {
            brc.browseDirection = UA_BROWSEDIRECTION_INVERSE;
            browseRecursiveCallback(&brc, &target);
        }
    }

    if(rt.size > 0 && brc.status == UA_STATUSCODE_GOOD) {
        *results = rt.targets;
        *resultsSize = rt.size;
    } else {
        RefTree_clear(&rt);
    }
    return brc.status;
}

UA_StatusCode
browseRecursiveRefTree(UA_Server *server, RefTree *rt, UA_BrowseDirection browseDirection,
                       const UA_ReferenceTypeSet *refTypes, UA_UInt32 nodeClassMask) {
    struct BrowseRecursiveContext brc;
    brc.server = server;
    brc.rt = rt;
    brc.depth = 0;
    brc.refTypes = *refTypes;
    brc.nodeClassMask = nodeClassMask;
    brc.status = UA_STATUSCODE_GOOD;
    brc.includeStartNodes = false;

    for(size_t i = 0; i < rt->size && brc.status == UA_STATUSCODE_GOOD; i++) {
        UA_ReferenceTarget target;
        UA_ExpandedNodeId current = rt->targets[i];
        target.targetId = UA_NodePointer_fromExpandedNodeId(&current);

        /* Call the inner recursive browse separately for the search direction.
         * Otherwise we might take one step up and another step down in the
         * search tree. */
        if(browseDirection == UA_BROWSEDIRECTION_FORWARD ||
           browseDirection == UA_BROWSEDIRECTION_BOTH) {
            brc.browseDirection = UA_BROWSEDIRECTION_FORWARD;
            browseRecursiveCallback(&brc, &target);
        }

        if(browseDirection == UA_BROWSEDIRECTION_INVERSE ||
           browseDirection == UA_BROWSEDIRECTION_BOTH) {
            brc.browseDirection = UA_BROWSEDIRECTION_INVERSE;
            browseRecursiveCallback(&brc, &target);
        }
    }

    return brc.status;
}

UA_StatusCode
UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
                          size_t *resultsSize, UA_ExpandedNodeId **results) {
    lockServer(server);

    /* Set the list of relevant reference types */
    UA_ReferenceTypeSet refTypes;
    UA_StatusCode retval = referenceTypeIndices(server, &bd->referenceTypeId,
                                                &refTypes, bd->includeSubtypes);
    if(retval != UA_STATUSCODE_GOOD) {
        unlockServer(server);
        return retval;
    }

    /* Browse */
    retval = browseRecursive(server, 1, &bd->nodeId, bd->browseDirection,
                             &refTypes, bd->nodeClassMask, false, resultsSize, results);

    unlockServer(server);
    return retval;
}

/**********/
/* Browse */
/**********/

typedef struct {
    size_t size;
    size_t capacity;
    UA_ReferenceDescription *descr;
} RefResult;

static UA_StatusCode UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
RefResult_init(RefResult *rr) {
    memset(rr, 0, sizeof(RefResult));
    rr->descr = (UA_ReferenceDescription*)
        UA_Array_new(UA_REFTREE_INITIAL_SIZE, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
    if(!rr->descr)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rr->capacity = UA_REFTREE_INITIAL_SIZE;
    rr->size = 0;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
RefResult_double(RefResult *rr) {
    size_t newSize = rr->capacity * 2;
    UA_ReferenceDescription *rd = (UA_ReferenceDescription*)
        UA_realloc(rr->descr, newSize * sizeof(UA_ReferenceDescription));
    if(!rd)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(&rd[rr->size], 0, sizeof(UA_ReferenceDescription) * (newSize - rr->size));
    rr->descr = rd;
    rr->capacity = newSize;
    return UA_STATUSCODE_GOOD;
}

static void
RefResult_clear(RefResult *rr) {
    UA_assert(rr->descr != NULL);
    for(size_t i = 0; i < rr->size; i++)
        UA_ReferenceDescription_clear(&rr->descr[i]);
    UA_free(rr->descr);
}

struct ContinuationPoint {
    ContinuationPoint *next;
    UA_ByteString identifier;

    /* Parameters of the Browse Request */
    UA_BrowseDescription browseDescription;
    UA_UInt32 maxReferences;
    UA_ReferenceTypeSet relevantReferences;

    /* The last reference target that was transmitted to the client. The results
     * list may be incomplete if the last target is removed or references added
     * between the calls to Browse/BrowseNext. */
    UA_NodePointer lastTarget;
    UA_Byte lastRefKindIndex;
    UA_Boolean lastRefInverse;
};

ContinuationPoint *
ContinuationPoint_clear(ContinuationPoint *cp) {
    UA_ByteString_clear(&cp->identifier);
    UA_BrowseDescription_clear(&cp->browseDescription);
    UA_NodePointer_clear(&cp->lastTarget);
    return cp->next;
}

struct BrowseContext {
    /* Context */
    ContinuationPoint *cp;
    UA_Server *server;
    UA_Session *session;
    UA_NodeReferenceKind *rk;
    UA_ReferenceTypeSet resultRefs; /* With additional references for type
                                     * lookups */
    UA_Boolean activeCP; /* true during "forwarding" to the position of the last
                          * reference target */

    /* Results */
    RefResult rr;
    UA_StatusCode status;
    UA_Boolean done;
};

/* Target node on top of the stack */
static UA_StatusCode
addReferenceDescription(struct BrowseContext *bc, UA_NodePointer nodeP,
                        const UA_Node *curr) {
    UA_assert(curr);
    UA_BrowseDescription *bd = &bc->cp->browseDescription;

    /* Ensure capacity is left */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(bc->rr.size >= bc->rr.capacity) {
        res = RefResult_double(&bc->rr);
        if(res != UA_STATUSCODE_GOOD)
           return res;
    }

    UA_ReferenceDescription *descr = &bc->rr.descr[bc->rr.size];

    /* Fields without access to the actual node */
    UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(nodeP);
    res = UA_ExpandedNodeId_copy(&en, &descr->nodeId);
    if(bd->resultMask & UA_BROWSERESULTMASK_REFERENCETYPEID) {
        const UA_NodeId *refTypeId =
            UA_NODESTORE_GETREFERENCETYPEID(bc->server, bc->rk->referenceTypeIndex);
        if(UA_LIKELY(refTypeId != NULL))
            res |= UA_NodeId_copy(refTypeId, &descr->referenceTypeId);
        else
            res |= UA_STATUSCODE_BADINTERNALERROR;
    }
    if(bd->resultMask & UA_BROWSERESULTMASK_ISFORWARD)
        descr->isForward = !bc->rk->isInverse;

    /* Create fields that require access to the actual node */
    if(bd->resultMask & UA_BROWSERESULTMASK_NODECLASS)
        descr->nodeClass = curr->head.nodeClass;

    if(bd->resultMask & UA_BROWSERESULTMASK_BROWSENAME)
        res |= UA_QualifiedName_copy(&curr->head.browseName,
                                     &descr->browseName);

    if(bd->resultMask & UA_BROWSERESULTMASK_DISPLAYNAME) {
        UA_LocalizedText displayname =
            UA_Session_getNodeDisplayName(bc->session, &curr->head);
        res |= UA_LocalizedText_copy(&displayname, &descr->displayName);
    }

    if(bd->resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION) {
        if(curr->head.nodeClass == UA_NODECLASS_OBJECT ||
           curr->head.nodeClass == UA_NODECLASS_VARIABLE) {
            const UA_Node *type =
                getNodeType(bc->server, &curr->head, 0,
                            UA_REFERENCETYPESET_NONE,
                            UA_BROWSEDIRECTION_INVALID);
            if(type) {
                res |= UA_NodeId_copy(&type->head.nodeId,
                                      &descr->typeDefinition.nodeId);
                UA_NODESTORE_RELEASE(bc->server, type);
            }
        }
    }

    /* Clean up and return */
    if(res != UA_STATUSCODE_GOOD) {
        UA_ReferenceDescription_clear(descr);
        return res;
    }
    bc->rr.size++;
    return UA_STATUSCODE_GOOD;
}

static void *
browseReferencTargetCallback(void *context, UA_ReferenceTarget *t) {
    struct BrowseContext *bc = (struct BrowseContext*)context;
    const UA_BrowseDescription *bd = &bc->cp->browseDescription;
    ContinuationPoint *cp = bc->cp;

    /* Remote references are ignored */
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;

    /* Include references only for figuring out the TypeDefinition within
     * addReferenceDescription. */
    UA_BrowseDirection direction = UA_BROWSEDIRECTION_INVALID;
    UA_ReferenceTypeSet refs = UA_REFERENCETYPESET_NONE;
    if(bd->resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION) {
        direction = UA_BROWSEDIRECTION_BOTH;
        UA_ReferenceTypeSet_add(&refs, UA_REFERENCETYPEINDEX_HASTYPEDEFINITION);
        UA_ReferenceTypeSet_add(&refs, UA_REFERENCETYPEINDEX_HASSUBTYPE);
    }
    
    /* Get the node */
    const UA_Node *target =
        UA_NODESTORE_GETFROMREF_SELECTIVE(bc->server, t->targetId,
                                          resultMask2AttributesMask(bd->resultMask),
                                          refs, direction);
    if(!target)
        return NULL;
    
    /* The node class has to match */
    if(!matchClassMask(target, bd->nodeClassMask)) {
        UA_NODESTORE_RELEASE(bc->server, target);
        return NULL;
    }
    
    /* Reached maxrefs. Return the "abort" signal. */
    if(bc->rr.size >= cp->maxReferences) {
        UA_NODESTORE_RELEASE(bc->server, target);
        return (void*)0x01;
    }

    /* Create the reference description */
    bc->status = addReferenceDescription(bc, t->targetId, target);

    /* Release the node */
    UA_NODESTORE_RELEASE(bc->server, target);

    /* Store as last target. The itarget-id is a shallow copy for now. */
    cp->lastTarget = t->targetId;
    cp->lastRefKindIndex = bc->rk->referenceTypeIndex;
    cp->lastRefInverse = bc->rk->isInverse;

    /* Abort if the status is not good. Also doesn't make a deep-copy of
     * cp->lastTarget after returning from here. */
    if(bc->status != UA_STATUSCODE_GOOD) {
        UA_NodePointer_init(&cp->lastTarget);
        return (void*)0x01;
    }
    return NULL;
}

/* Returns whether the node / continuationpoint is done */
static void
browseWithNode(struct BrowseContext *bc, const UA_NodeHead *head ) {
    ContinuationPoint *cp = bc->cp;
    const UA_BrowseDescription *bd = &cp->browseDescription;

    /* Loop over the ReferenceKinds */
    for(size_t i = 0; i < head->referencesSize && bc->status == UA_STATUSCODE_GOOD; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];

        /* If the continuation point was previously used, skip forward to the
         * last ReferenceType that was transmitted */
        if(bc->activeCP && rk->referenceTypeIndex != cp->lastRefKindIndex)
            continue;
        if(bc->activeCP && rk->isInverse != cp->lastRefInverse)
            continue;

        /* Reference in the right direction? */
        if(rk->isInverse && bd->browseDirection == UA_BROWSEDIRECTION_FORWARD)
            continue;
        if(!rk->isInverse && bd->browseDirection == UA_BROWSEDIRECTION_INVERSE)
            continue;

        /* Is the reference part of the hierarchy of references we look for? */
        if(!UA_ReferenceTypeSet_contains(&cp->relevantReferences, rk->referenceTypeIndex))
            continue;

        /* We have a matching ReferenceKind */

        /* Skip ahead to the target where the last continuation point stopped.
         * This temporarily modifies rk. */
        UA_ReferenceIdTree left = {NULL}, right = {NULL};
        size_t nextTargetIndex = 0;
        if(bc->activeCP) {
            if(rk->hasRefTree) {
                /* Unzip the tree until the continuation point. All NodeIds
                 * larger than the last target are guaranteed to sit on the
                 * right-hand side. */
                UA_ExpandedNodeId lastEn =
                    UA_NodePointer_toExpandedNodeId(cp->lastTarget);
                UA_ReferenceTargetTreeElem key;
                key.target.targetId = cp->lastTarget;
                key.targetIdHash = UA_ExpandedNodeId_hash(&lastEn);
                ZIP_UNZIP(UA_ReferenceIdTree,
                          (UA_ReferenceIdTree*)&rk->targets.tree.idRoot,
                          &key, &left, &right);
                rk->targets.tree.idRoot = right.root;
            } else {
                /* Iterate over the array to find the match */
                for(; nextTargetIndex < rk->targetsSize; nextTargetIndex++) {
                    UA_ReferenceTarget *t = &rk->targets.array[nextTargetIndex];
                    if(UA_NodePointer_equal(cp->lastTarget, t->targetId))
                        break;
                }
                if(nextTargetIndex == rk->targetsSize) {
                    /* Not found - assume that this reference kind is done */
                    bc->activeCP = false;
                    continue;
                }
                nextTargetIndex++; /* From the last index to the next index */
                rk->targets.array = &rk->targets.array[nextTargetIndex];
                rk->targetsSize -= nextTargetIndex;
            }

            /* Clear cp->lastTarget before it gets overwritten in the following
             * browse steps. */
            UA_NodePointer_clear(&cp->lastTarget);
        }

        /* Iterate over all reference targets */
        bc->rk = rk;
        void *res = UA_NodeReferenceKind_iterate(rk, browseReferencTargetCallback, bc);

        /* Undo the "skipping ahead" for the continuation point */
        if(bc->activeCP) {
            if(rk->hasRefTree) {
                rk->targets.tree.idRoot =
                    ZIP_ZIP(UA_ReferenceIdTree, left.root, right.root);
            } else {
                /* rk->targets.array = rk->targets.array[-nextTargetIndex]; */
                rk->targets.array = rk->targets.array - nextTargetIndex;
                rk->targetsSize += nextTargetIndex;
                UA_assert(rk->targetsSize > 0);
            }
            bc->activeCP = false;
        }

        /* The iteration was aborted */
        if(res != NULL) {
            /* Aborted with status code good -> the maximum number of browse
             * results was reached. Make a deep copy of the last target for the
             * continuation point. */
            if(bc->status == UA_STATUSCODE_GOOD)
                bc->status = UA_NodePointer_copy(cp->lastTarget, &cp->lastTarget);
            return;
        }
    }

    /* Reset last-target to prevent clearing it up */
    UA_NodePointer_init(&cp->lastTarget);

    /* Browsing the node is done */
    bc->done = true;
}

/* Results for a single browsedescription. This is the inner loop for both
 * Browse and BrowseNext. The ContinuationPoint contains all the data used.
 * Including the BrowseDescription. Returns whether there are remaining
 * references. */
static void
browse(struct BrowseContext *bc) {
    /* Is the browsedirection valid? */
    struct ContinuationPoint *cp = bc->cp;
    const UA_BrowseDescription *descr = &cp->browseDescription;
    if(descr->browseDirection != UA_BROWSEDIRECTION_BOTH &&
       descr->browseDirection != UA_BROWSEDIRECTION_FORWARD &&
       descr->browseDirection != UA_BROWSEDIRECTION_INVERSE) {
        bc->status = UA_STATUSCODE_BADBROWSEDIRECTIONINVALID;
        return;
    }

    /* Get node with only the selected references and attributes */
    const UA_Node *node =
        UA_NODESTORE_GET_SELECTIVE(bc->server, &descr->nodeId,
                                   resultMask2AttributesMask(descr->resultMask),
                                   bc->resultRefs, descr->browseDirection);
    if(!node) {
        bc->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return;
    }

    /* Check AccessControl rights */
    if(bc->session != &bc->server->adminSession) {
        UA_LOCK_ASSERT(&bc->server->serviceMutex);
        if(!bc->server->config.accessControl.
           allowBrowseNode(bc->server, &bc->server->config.accessControl,
                           &bc->session->sessionId, bc->session->context,
                           &descr->nodeId, node->head.context)) {
            UA_NODESTORE_RELEASE(bc->server, node);
            bc->status = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
    }

    /* Browse the node */
    browseWithNode(bc, &node->head);
    UA_NODESTORE_RELEASE(bc->server, node);

    /* Is the reference type valid? This is very infrequent. So we only test
     * this if browsing came up empty. If the node has references of that type,
     * we know the reftype to be good. */
    if(bc->rr.size == 0 && !UA_NodeId_isNull(&descr->referenceTypeId)) {
        const UA_Node *reftype =
            UA_NODESTORE_GET_SELECTIVE(bc->server, &descr->referenceTypeId,
                                       UA_NODEATTRIBUTESMASK_NODECLASS,
                                       UA_REFERENCETYPESET_NONE,
                                       UA_BROWSEDIRECTION_INVALID);
        if(!reftype) {
            bc->status = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
            return;
        }

        UA_Boolean isRef = (reftype->head.nodeClass == UA_NODECLASS_REFERENCETYPE);
        UA_NODESTORE_RELEASE(bc->server, reftype);

        if(!isRef) {
            bc->status = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
            return;
        }
    }
}

/* Start to browse with no previous cp */
void
Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxrefs,
                 const UA_BrowseDescription *descr, UA_BrowseResult *result) {
    /* Stack-allocate a temporary cp */
    ContinuationPoint cp;
    memset(&cp, 0, sizeof(ContinuationPoint));
    cp.maxReferences = *maxrefs;
    cp.browseDescription = *descr; /* Shallow copy. Deep-copy later if we persist the cp. */

    /* How many references can we return at most? */
    if(cp.maxReferences == 0) {
        if(server->config.maxReferencesPerNode != 0) {
            cp.maxReferences = server->config.maxReferencesPerNode;
        } else {
            cp.maxReferences = UA_INT32_MAX;
        }
    } else {
        if(server->config.maxReferencesPerNode != 0 &&
           cp.maxReferences > server->config.maxReferencesPerNode) {
            cp.maxReferences= server->config.maxReferencesPerNode;
        }
    }

    /* Get the list of relevant reference types */
    result->statusCode =
        referenceTypeIndices(server, &descr->referenceTypeId,
                             &cp.relevantReferences, descr->includeSubtypes);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Prepare the context */
    struct BrowseContext bc;
    bc.cp = &cp;
    bc.server = server;
    bc.session = session;
    bc.status = UA_STATUSCODE_GOOD;
    bc.done = false;
    bc.activeCP = false;
    bc.resultRefs = cp.relevantReferences;
    result->statusCode = RefResult_init(&bc.rr);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Perform the browse */
    browse(&bc);

    if(bc.status != UA_STATUSCODE_GOOD || bc.rr.size == 0) {
        /* No relevant references, return array of length zero */
        RefResult_clear(&bc.rr);
        result->references = (UA_ReferenceDescription*)UA_EMPTY_ARRAY_SENTINEL;
        result->statusCode = bc.status;
        return;
    }

    /* Move results */
    result->references = bc.rr.descr;
    result->referencesSize = bc.rr.size;

    /* Exit early if done */
    if(bc.done)
        return;

    /* Persist the continuation point */

    ContinuationPoint *cp2 = NULL;
    UA_Guid *ident = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Enough space for the continuation point? */
    if(session->availableContinuationPoints == 0) {
        retval = UA_STATUSCODE_BADNOCONTINUATIONPOINTS;
        goto cleanup;
    }

    /* Allocate and fill the data structure */
    cp2 = (ContinuationPoint*)UA_calloc(1, sizeof(ContinuationPoint));
    if(!cp2) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    /* The BrowseDescription is only a shallow copy so far */
    retval = UA_BrowseDescription_copy(descr, &cp2->browseDescription);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;
    cp2->maxReferences = cp.maxReferences;
    cp2->relevantReferences = cp.relevantReferences;
    cp2->lastTarget = cp.lastTarget; /* Move the (deep) copy */
    UA_NodePointer_init(&cp.lastTarget); /* No longer clear below (cleanup) */
    cp2->lastRefKindIndex = cp.lastRefKindIndex;
    cp2->lastRefInverse = cp.lastRefInverse;

    /* Create a random bytestring via a Guid */
    ident = UA_Guid_new();
    if(!ident) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }
    *ident = UA_Guid_random();
    cp2->identifier.data = (UA_Byte*)ident;
    cp2->identifier.length = sizeof(UA_Guid);

    /* Return the cp identifier */
    retval = UA_ByteString_copy(&cp2->identifier, &result->continuationPoint);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Attach the cp to the session */
    cp2->next = session->continuationPoints;
    session->continuationPoints = cp2;
    --session->availableContinuationPoints;
    return;

 cleanup:
    if(cp2) {
        ContinuationPoint_clear(cp2);
        UA_free(cp2);
    }
    UA_NodePointer_clear(&cp.lastTarget);
    UA_BrowseResult_clear(result);
    result->statusCode = retval;
}

UA_Boolean
Service_Browse(UA_Server *server, UA_Session *session,
               const UA_BrowseRequest *request, UA_BrowseResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing BrowseRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Test the number of operations in the request */
    if(server->config.maxNodesPerBrowse != 0 &&
       request->nodesToBrowseSize > server->config.maxNodesPerBrowse) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    /* No views supported at the moment */
    if(!UA_NodeId_isNull(&request->view.viewId)) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADVIEWIDUNKNOWN;
        return true;
    }

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_Browse,
                                      &request->requestedMaxReferencesPerNode,
                                      &request->nodesToBrowseSize,
                                      &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_BROWSERESULT]);
    return true;
}

UA_BrowseResult
UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences,
                 const UA_BrowseDescription *bd) {
    UA_BrowseResult result;
    UA_BrowseResult_init(&result);
    lockServer(server);
    Operation_Browse(server, &server->adminSession, &maxReferences, bd, &result);
    unlockServer(server);
    return result;
}

static void
Operation_BrowseNext(UA_Server *server, UA_Session *session,
                     const UA_Boolean *releaseContinuationPoints,
                     const UA_ByteString *continuationPoint, UA_BrowseResult *result) {
    /* Find the continuation point */
    ContinuationPoint **prev = &session->continuationPoints;
    ContinuationPoint *cp;
    while((cp = *prev)) {
        if(UA_ByteString_equal(&cp->identifier, continuationPoint))
            break;
        prev = &cp->next;
    }
    if(!cp) {
        result->statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        return;
    }

    /* Remove the cp */
    if(*releaseContinuationPoints) {
        *prev = ContinuationPoint_clear(cp);
        UA_free(cp);
        ++session->availableContinuationPoints;
        return;
    }

    /* Prepare the context */
    struct BrowseContext bc;
    bc.cp = cp;
    bc.server = server;
    bc.session = session;
    bc.status = UA_STATUSCODE_GOOD;
    bc.done = false;
    bc.activeCP = true;
    bc.resultRefs = cp->relevantReferences;
    result->statusCode = RefResult_init(&bc.rr);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Continue browsing */
    browse(&bc);

    if(bc.status != UA_STATUSCODE_GOOD || bc.rr.size == 0) {
        /* No relevant references, return array of length zero */
        RefResult_clear(&bc.rr);
        result->references = (UA_ReferenceDescription*)UA_EMPTY_ARRAY_SENTINEL;
        result->statusCode = bc.status;
        goto remove_cp;
    }

    /* Move results */
    result->references = bc.rr.descr;
    result->referencesSize = bc.rr.size;

    if(bc.done)
        goto remove_cp;

    /* Return the cp identifier to signal that there are references left */
    bc.status = UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
    if(bc.status != UA_STATUSCODE_GOOD) {
        UA_BrowseResult_clear(result);
        result->statusCode = bc.status;
    }
    return;

 remove_cp:
    /* Remove the cp */
    *prev = ContinuationPoint_clear(cp);
    UA_free(cp);
    ++session->availableContinuationPoints;
}

UA_Boolean
Service_BrowseNext(UA_Server *server, UA_Session *session,
                   const UA_BrowseNextRequest *request,
                   UA_BrowseNextResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing BrowseNextRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Boolean releaseContinuationPoints =
        request->releaseContinuationPoints; /* request is const */
    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_BrowseNext,
                                      &releaseContinuationPoints,
                                      &request->continuationPointsSize,
                                      &UA_TYPES[UA_TYPES_BYTESTRING],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_BROWSERESULT]);
    return true;
}

UA_BrowseResult
UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
                     const UA_ByteString *continuationPoint) {
    UA_BrowseResult result;
    UA_BrowseResult_init(&result);
    lockServer(server);
    Operation_BrowseNext(server, &server->adminSession, &releaseContinuationPoint,
                         continuationPoint, &result);
    unlockServer(server);
    return result;
}

/***********************/
/* TranslateBrowsePath */
/***********************/

/* Add all entries for the hash. There are possible duplicates due to hash
 * collisions. The full browsename is checked afterwards. */
static void *
addBrowseHashTarget(void *context, UA_ReferenceTargetTreeElem *elem) {
    RefTree *next = (RefTree*)context;
    return (void*)(uintptr_t)RefTree_add(next, elem->target.targetId, NULL);
}

static UA_StatusCode
walkBrowsePathElement(UA_Server *server, UA_Session *session,
                      const UA_RelativePath *path, const size_t pathIndex,
                      UA_UInt32 nodeClassMask, const UA_QualifiedName *lastBrowseName,
                      UA_BrowsePathResult *result, RefTree *current, RefTree *next) {
    /* For the next level. Note the difference from lastBrowseName */
    const UA_RelativePathElement *elem = &path->elements[pathIndex];
    UA_UInt32 browseNameHash = UA_QualifiedName_hash(&elem->targetName);

    /* Get the relevant ReferenceTypes */
    UA_ReferenceTypeSet refTypes;
    UA_StatusCode res =
        referenceTypeIndices(server, &elem->referenceTypeId,
                             &refTypes, elem->includeSubtypes);
    if(res != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADNOMATCH;

    /* Loop over all Nodes in the current depth level */
    for(size_t i = 0; i < current->size; i++) {
        /* Remote Node. Immediately add to the results with the
         * RemainingPathIndex set. */
        if(!UA_ExpandedNodeId_isLocal(&current->targets[i])) {
            /* Increase the size of the results array */
            UA_BrowsePathTarget *tmpResults = (UA_BrowsePathTarget*)
                UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) *
                           (result->targetsSize + 1));
            if(!tmpResults)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            result->targets = tmpResults;

            /* Copy over the result */
            UA_BrowsePathTarget *newEntry = &result->targets[result->targetsSize];
            res = UA_ExpandedNodeId_copy(&current->targets[i], &newEntry->targetId);
            newEntry->remainingPathIndex = (UA_UInt32)pathIndex;
            result->targetsSize++;
            if(res != UA_STATUSCODE_GOOD)
                break;
            continue;
        }

        /* Local Node. Add to the tree of results at the next depth. Get only
         * the NodeClass + BrowseName attribute and the selected ReferenceTypes
         * if the nodestore supports that. */
        const UA_Node *node =
            UA_NODESTORE_GET_SELECTIVE(server, &current->targets[i].nodeId,
                                       UA_NODEATTRIBUTESMASK_NODECLASS |
                                       UA_NODEATTRIBUTESMASK_BROWSENAME,
                                       refTypes,
                                       elem->isInverse ? UA_BROWSEDIRECTION_INVERSE :
                                                         UA_BROWSEDIRECTION_FORWARD);
        if(!node)
            continue;

        /* Check whether the session is allowed to browse this node.
         * Mirrors the access-control gate applied in browseWithContinuation().
         * Without this check, a client denied direct Browse on a node can
         * still use it as a waypoint in TranslateBrowsePathsToNodeIds,
         * disclosing hidden intermediate nodes and their children. */
        if(session != &server->adminSession) {
            UA_UNLOCK(&server->serviceMutex);
            UA_Boolean canBrowse =
                server->config.accessControl.allowBrowseNode(
                    server, &server->config.accessControl,
                    &session->sessionId, session->context,
                    &current->targets[i].nodeId, node->head.context);
            UA_LOCK(&server->serviceMutex);
            if(!canBrowse) {
                UA_NODESTORE_RELEASE(server, node);
                continue;
            }
        }

        /* Test whether the node fits the class mask */
        UA_Boolean skip = !matchClassMask(node, nodeClassMask);

        /* Does the BrowseName match for the current node (not the references
         * going out here) */
        skip |= (lastBrowseName &&
                 !UA_QualifiedName_equal(lastBrowseName, &node->head.browseName));

        if(skip) {
            UA_NODESTORE_RELEASE(server, node);
            continue;
        }

        /* Loop over the ReferenceKinds */
        UA_ReferenceTarget targetHashKey;
        targetHashKey.targetNameHash = browseNameHash;
        for(size_t j = 0; j < node->head.referencesSize; j++) {
            UA_NodeReferenceKind *rk = &node->head.references[j];

            /* Does the direction of the reference match? */
            if(rk->isInverse != elem->isInverse)
                continue;

            /* Does the reference type match? */
            if(!UA_ReferenceTypeSet_contains(&refTypes, rk->referenceTypeIndex))
                continue;

            /* Retrieve by BrowseName hash. We might have several nodes where
             * the hash matches. The exact BrowseName will be verified in the
             * next iteration of the outer loop. So we only have to retrieve
             * every node just once. */

            if(rk->hasRefTree) {
                res = (UA_StatusCode)(uintptr_t)
                    ZIP_ITER_KEY(UA_ReferenceNameTree,
                                 (UA_ReferenceNameTree*)&rk->targets.tree.nameRoot,
                                 &targetHashKey, addBrowseHashTarget, next);
                if(res != UA_STATUSCODE_GOOD)
                    break;
            } else {
                /* The array entries don't have a BrowseName hash. Add all of
                 * them at this level to be checked with a full string
                 * comparison. */
                for(size_t k = 0; k < rk->targetsSize; k++) {
                    if(rk->targets.array[k].targetNameHash != browseNameHash)
                        continue;
                    res = RefTree_add(next, rk->targets.array[k].targetId, NULL);
                    if(res != UA_STATUSCODE_GOOD)
                        break;
                }
                if(res != UA_STATUSCODE_GOOD)
                    break;
            }
        }

        UA_NODESTORE_RELEASE(server, node);
    }
    return res;
}

static void
Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session,
                                       const UA_UInt32 *nodeClassMask,
                                       const UA_BrowsePath *path,
                                       UA_BrowsePathResult *result) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(path->relativePath.elementsSize == 0) {
        result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
        return;
    }

    /* RelativePath elements must not have an empty targetName */
    for(size_t i = 0; i < path->relativePath.elementsSize; ++i) {
        if(UA_QualifiedName_isNull(&path->relativePath.elements[i].targetName)) {
            result->statusCode = UA_STATUSCODE_BADBROWSENAMEINVALID;
            return;
        }
    }

    /* Check if the starting node exists */
    const UA_Node *startingNode =
        UA_NODESTORE_GET_SELECTIVE(server, &path->startingNode,
                                   UA_NODEATTRIBUTESMASK_NONE,
                                   UA_REFERENCETYPESET_NONE,
                                   UA_BROWSEDIRECTION_INVALID);
    if(!startingNode) {
        result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return;
    }
    UA_NODESTORE_RELEASE(server, startingNode);

    /* Create two RefTrees that are alternated between path elements */
    RefTree rt1;
    RefTree rt2;
    RefTree *current = &rt1;
    RefTree *next = &rt2;
    RefTree *tmp;
    result->statusCode |= RefTree_init(&rt1);
    result->statusCode |= RefTree_init(&rt2);
    UA_BrowsePathTarget *tmpResults = NULL;
    UA_QualifiedName *browseNameFilter = NULL;
    if(result->statusCode != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Copy the starting node into next */
    result->statusCode = RefTree_addNodeId(next, &path->startingNode, NULL);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Walk the path elements. Retrieve the nodes only once from the NodeStore.
     * Hence the BrowseName is checked with one element "delay". */
    for(size_t i = 0; i < path->relativePath.elementsSize; i++) {
        /* Switch the trees */
        tmp = current;
        current = next;
        next = tmp;

        /* Clear up current, keep the capacity */
        for(size_t j = 0; j < next->size; j++)
            UA_ExpandedNodeId_clear(&next->targets[j]);
        next->size = 0;
        ZIP_INIT(&next->head);

        /* Do this check after next->size has been set to zero */
        if(current->size == 0)
            break;

        /* Walk element for all NodeIds in the "current" tree.
         * Puts new results in the "next" tree. */
        result->statusCode =
            walkBrowsePathElement(server, session, &path->relativePath, i,
                                  *nodeClassMask, browseNameFilter, result, current, next);
        if(result->statusCode != UA_STATUSCODE_GOOD)
            goto cleanup;

        browseNameFilter = &path->relativePath.elements[i].targetName;
    }

    /* Allocate space for the results array */
    tmpResults = (UA_BrowsePathTarget*)
        UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) *
                   (result->targetsSize + next->size));
    if(!tmpResults && next->size > 0) {
        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }
    result->targets = tmpResults;

    for(size_t k = 0; k < next->size; k++) {
        /* Check the BrowseName. It has been filtered only via its hash so far.
         * Get only the BrowseName attribute if the nodestore supports that. */
        const UA_Node *node =
            UA_NODESTORE_GET_SELECTIVE(server, &next->targets[k].nodeId,
                                       UA_NODEATTRIBUTESMASK_BROWSENAME,
                                       UA_REFERENCETYPESET_NONE,
                                       UA_BROWSEDIRECTION_INVALID);
        if(!node)
            continue;

        /* Check whether the session is allowed to browse the resolved target.
         * Without this check, a client denied direct Browse on a terminal node
         * can still have its NodeId disclosed as the result of path
         * translation. */
        if(session != &server->adminSession) {
            UA_UNLOCK(&server->serviceMutex);
            UA_Boolean canBrowse =
                server->config.accessControl.allowBrowseNode(
                    server, &server->config.accessControl,
                    &session->sessionId, session->context,
                    &next->targets[k].nodeId, node->head.context);
            UA_LOCK(&server->serviceMutex);
            if(!canBrowse) {
                UA_NODESTORE_RELEASE(server, node);
                continue;
            }
        }

        UA_Boolean match = UA_QualifiedName_equal(browseNameFilter, &node->head.browseName);
        UA_NODESTORE_RELEASE(server, node);
        if(!match)
            continue;

        /* Move the target to the results array */
        result->targets[result->targetsSize].targetId = next->targets[k];
        result->targets[result->targetsSize].remainingPathIndex = UA_UINT32_MAX;
        UA_ExpandedNodeId_init(&next->targets[k]);
        result->targetsSize++;
    }

    /* No results => BadNoMatch status code */
    if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD)
        result->statusCode = UA_STATUSCODE_BADNOMATCH;

    /* Clean up the temporary arrays and the targets */
 cleanup:
    RefTree_clear(&rt1);
    RefTree_clear(&rt2);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        for(size_t i = 0; i < result->targetsSize; ++i)
            UA_BrowsePathTarget_clear(&result->targets[i]);
        if(result->targets)
            UA_free(result->targets);
        result->targets = NULL;
        result->targetsSize = 0;
    }
}

UA_BrowsePathResult
translateBrowsePathToNodeIds(UA_Server *server,
                             const UA_BrowsePath *browsePath) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_BrowsePathResult result;
    UA_BrowsePathResult_init(&result);
    UA_UInt32 nodeClassMask = 0; /* All node classes */
    Operation_TranslateBrowsePathToNodeIds(server, &server->adminSession, &nodeClassMask,
                                           browsePath, &result);
    return result;
}

UA_BrowsePathResult
UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
                                       const UA_BrowsePath *browsePath) {
    lockServer(server);
    UA_BrowsePathResult result = translateBrowsePathToNodeIds(server, browsePath);
    unlockServer(server);
    return result;
}

UA_Boolean
Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
                                      const UA_TranslateBrowsePathsToNodeIdsRequest *request,
                                      UA_TranslateBrowsePathsToNodeIdsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing TranslateBrowsePathsToNodeIdsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Test the number of operations in the request */
    if(server->config.maxNodesPerTranslateBrowsePathsToNodeIds != 0 &&
       request->browsePathsSize > server->config.maxNodesPerTranslateBrowsePathsToNodeIds) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    UA_UInt32 nodeClassMask = 0; /* All node classes */
    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_TranslateBrowsePathToNodeIds,
                                      &nodeClassMask, &request->browsePathsSize,
                                      &UA_TYPES[UA_TYPES_BROWSEPATH], &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]);
    return true;
}

UA_BrowsePathResult
browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
                           size_t browsePathSize, const UA_QualifiedName *browsePath) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_BrowsePathResult bpr;
    UA_BrowsePathResult_init(&bpr);
    if(browsePathSize > UA_MAX_TREE_RECURSE) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Simplified Browse Path too long");
        bpr.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return bpr;
    }

    /* Construct the BrowsePath */
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = origin;

    UA_RelativePathElement rpe[UA_MAX_TREE_RECURSE];
    memset(rpe, 0, sizeof(UA_RelativePathElement) * browsePathSize);
    for(size_t j = 0; j < browsePathSize; j++) {
        rpe[j].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
        rpe[j].includeSubtypes = true;
        rpe[j].targetName = browsePath[j];
    }
    bp.relativePath.elements = rpe;
    bp.relativePath.elementsSize = browsePathSize;

    /* Browse */
    UA_UInt32 nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_OBJECTTYPE;

    Operation_TranslateBrowsePathToNodeIds(server, &server->adminSession, &nodeClassMask, &bp, &bpr);
    return bpr;
}

UA_BrowsePathResult
UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
                           size_t browsePathSize, const UA_QualifiedName *browsePath) {
    lockServer(server);
    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, origin, browsePathSize, browsePath);
    unlockServer(server);
    return bpr;
}

/************/
/* Register */
/************/

UA_Boolean
Service_RegisterNodes(UA_Server *server, UA_Session *session,
                      const UA_RegisterNodesRequest *request,
                      UA_RegisterNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RegisterNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    //TODO: hang the nodeids to the session if really needed
    if(request->nodesToRegisterSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return true;
    }

    /* Test the number of operations in the request */
    if(server->config.maxNodesPerRegisterNodes != 0 &&
       request->nodesToRegisterSize > server->config.maxNodesPerRegisterNodes) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    response->responseHeader.serviceResult =
        UA_Array_copy(request->nodesToRegister, request->nodesToRegisterSize,
                      (void**)&response->registeredNodeIds, &UA_TYPES[UA_TYPES_NODEID]);
    if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
        response->registeredNodeIdsSize = request->nodesToRegisterSize;

    return true;
}

UA_Boolean
Service_UnregisterNodes(UA_Server *server, UA_Session *session,
                        const UA_UnregisterNodesRequest *request,
                        UA_UnregisterNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing UnRegisterNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(request->nodesToUnregisterSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
    } else if(server->config.maxNodesPerRegisterNodes != 0 &&
              request->nodesToUnregisterSize > server->config.maxNodesPerRegisterNodes) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
    }

    return true;
}

/**** amalgamated original file "/src/server/ua_services_method.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2017 (c) Florian Palm
 *    Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) LEvertz
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2020 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
 *    Copyright (c) 2025 Pilz GmbH & Co. KG, Author: Marcel Patzlaff
 */


#ifdef UA_ENABLE_METHODCALLS /* conditional compilation */

#define UA_MAX_METHOD_ARGUMENTS 64

struct GetArgumentsNodeContext {
    UA_Server *server;
    UA_String withBrowseName;
};

static void *
getArgumentsNodeCallback(void *context, UA_ReferenceTarget *t) {
    struct GetArgumentsNodeContext *ctx = (struct GetArgumentsNodeContext*)context;
    const UA_Node *refTarget =
        UA_NODESTORE_GETFROMREF_SELECTIVE(ctx->server, t->targetId,
                                          UA_NODEATTRIBUTESMASK_NODECLASS |
                                          UA_NODEATTRIBUTESMASK_VALUE,
                                          UA_REFERENCETYPESET_NONE,
                                          UA_BROWSEDIRECTION_INVALID);
    if(!refTarget)
        return NULL;
    if(refTarget->head.nodeClass == UA_NODECLASS_VARIABLE &&
       refTarget->head.browseName.namespaceIndex == 0 &&
       UA_String_equal(&ctx->withBrowseName, &refTarget->head.browseName.name)) {
        return (void*)(uintptr_t)&refTarget->variableNode;
    }
    UA_NODESTORE_RELEASE(ctx->server, refTarget);
    return NULL;
}

static const UA_VariableNode *
getArgumentsVariableNode(UA_Server *server, const UA_NodeHead *head,
                         UA_String withBrowseName) {
    for(size_t i = 0; i < head->referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(rk->isInverse)
            continue;
        if(rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASPROPERTY)
            continue;
        struct GetArgumentsNodeContext ctx;
        ctx.server = server;
        ctx.withBrowseName = withBrowseName;
        return (const UA_VariableNode*)
            UA_NodeReferenceKind_iterate(rk, getArgumentsNodeCallback, &ctx);
    }
    return NULL;
}

/* inputArgumentResults has the length request->inputArgumentsSize */
static UA_StatusCode
checkAdjustArguments(UA_Server *server, UA_Session *session,
                     const UA_VariableNode *argRequirements, size_t argsSize,
                     UA_Variant *args, UA_StatusCode *inputArgumentResults) {
    /* Verify that we have a Variant containing UA_Argument (scalar or array) in
     * the "InputArguments" node */
    if(argRequirements->valueSourceType != UA_VALUESOURCETYPE_INTERNAL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(!argRequirements->valueSource.internal.value.hasValue)
        return UA_STATUSCODE_BADINTERNALERROR;

    const UA_Variant *argVal = &argRequirements->valueSource.internal.value.value;
    if(argVal->type != &UA_TYPES[UA_TYPES_ARGUMENT])
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Verify the number of arguments. A scalar argument value is interpreted as
     * an array of length 1. */
    size_t argReqsSize = argVal->arrayLength;
    if(UA_Variant_isScalar(argVal))
        argReqsSize = 1;
    if(argReqsSize > argsSize)
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    if(argReqsSize < argsSize)
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;

    /* Type-check every argument against the definition */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_Argument *argReqs = (UA_Argument*)argVal->data;
    const char *reason;
    for(size_t i = 0; i < argReqsSize; ++i) {
        /* Incompatible value. Try to correct the type if possible. */
        adjustValueType(server, &args[i], &argReqs[i].dataType);

        /* Check */
        if(!compatibleValue(server, session, &argReqs[i].dataType, argReqs[i].valueRank,
                            argReqs[i].arrayDimensionsSize, argReqs[i].arrayDimensions,
                            &args[i], NULL, &reason)) {
            inputArgumentResults[i] = UA_STATUSCODE_BADTYPEMISMATCH;
            retval = UA_STATUSCODE_BADINVALIDARGUMENT;
        }
    }
    return retval;
}

static UA_StatusCode
checkMethodInTypeHierarchy(UA_Server *server, UA_Session *session,
                           const UA_NodeId *contextId, const UA_NodeId *methodId,
                           const UA_QualifiedName *methodBrowseName) {
    /* Get the type hierarchy "upwards" from the context */
    UA_NodeId *typeHierarchy;
    size_t typeHierarchySize;
    UA_StatusCode res =
        getTypeAndInterfaceHierarchy(server, contextId, false,
                                     &typeHierarchy, &typeHierarchySize);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Check if the method is in the type hierarchy */
    for(size_t i = 0; i < typeHierarchySize; i++) {
        UA_NodeId contained;
        res = findChildByBrowsename(server, session, typeHierarchy[i],
                                    UA_NODECLASS_METHOD,
                                    UA_REFERENCETYPEINDEX_HASCOMPONENT,
                                    UA_NS0ID(HASCOMPONENT),
                                    methodBrowseName, &contained);
        if(res == UA_STATUSCODE_BADNOTFOUND)
            continue;
        if(res != UA_STATUSCODE_GOOD)
            break;
        UA_Boolean found = UA_NodeId_equal(&contained, methodId);
        UA_NodeId_clear(&contained);
        res = (found) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOTFOUND;
        if(found)
            break;
    }

    /* Clean up and return */
    UA_Array_delete(typeHierarchy, typeHierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
    return res;
}

static UA_StatusCode
callWithResolvedMethodAndObject(UA_Server *server, UA_Session *session,
                                const UA_CallMethodRequest *request,
                                UA_CallMethodResult *result,
                                const UA_MethodNode *resolvedMethod,
                                const UA_Node *callContext) {
    /* Is there a method to execute? */
    if(!resolvedMethod->method)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Verify access rights */
    UA_Boolean executable = resolvedMethod->executable;
    if(!executable)
        return UA_STATUSCODE_BADNOTEXECUTABLE;

    if(session != &server->adminSession) {
        executable = server->config.accessControl.
            getUserExecutableOnObject(server, &server->config.accessControl,
                                      &session->sessionId, session->context,
                                      &resolvedMethod->head.nodeId,
                                      resolvedMethod->head.context,
                                      &request->objectId,
                                      callContext->head.context);
    }
    if(!executable)
        return UA_STATUSCODE_BADUSERACCESSDENIED;

    /* The input arguments are const and not changed. We move the input
     * arguments to a secondary array that is mutable. This is used for small
     * adjustments on the type level during the type checking. But it has to be
     * ensured that the original array can still by _clear'ed after the methods
     * call. */
    if(request->inputArgumentsSize > UA_MAX_METHOD_ARGUMENTS)
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;

    UA_Variant mutableInputArgs[UA_MAX_METHOD_ARGUMENTS];
    if(request->inputArgumentsSize > 0)
        memcpy(mutableInputArgs, request->inputArguments,
               sizeof(UA_Variant) * request->inputArgumentsSize);

    /* Allocate the inputArgumentResults array */
    result->inputArgumentResults = (UA_StatusCode*)
        UA_Array_new(request->inputArgumentsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
    if(!result->inputArgumentResults)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    result->inputArgumentResultsSize = request->inputArgumentsSize;

    /* Type-check the input arguments */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_VariableNode *inputArguments =
        getArgumentsVariableNode(server, &resolvedMethod->head,
                                 UA_STRING("InputArguments"));
    if(inputArguments) {
        res = checkAdjustArguments(server, session,
                                   inputArguments, request->inputArgumentsSize,
                                   mutableInputArgs, result->inputArgumentResults);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)inputArguments);
    } else if(request->inputArgumentsSize > 0) {
        res = UA_STATUSCODE_BADTOOMANYARGUMENTS;
    }

    /* Return inputArgumentResults only for BADINVALIDARGUMENT */
    if(res != UA_STATUSCODE_BADINVALIDARGUMENT) {
        UA_Array_delete(result->inputArgumentResults,
                        result->inputArgumentResultsSize,
                        &UA_TYPES[UA_TYPES_STATUSCODE]);
        result->inputArgumentResults = NULL;
        result->inputArgumentResultsSize = 0;
    }

    /* Error during type-checking? */
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Get the output arguments node */
    const UA_VariableNode *outputArguments =
        getArgumentsVariableNode(server, &resolvedMethod->head,
                                 UA_STRING("OutputArguments"));

    /* Allocate the output arguments array. Always allocate memory, hence the
     * +1, even if the length is zero. Because we need a unique outputArguments
     * pointer as the key for async operations. The memory gets deleted in
     * UA_Array_delete even if the outputArgumentsSize is zero. */
    size_t outputArgsSize = 0;
    if(outputArguments)
        outputArgsSize = outputArguments->valueSource.internal.value.value.arrayLength;
    result->outputArguments = (UA_Variant*)
        UA_Array_new(outputArgsSize+1, &UA_TYPES[UA_TYPES_VARIANT]);
    if(!result->outputArguments)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    result->outputArgumentsSize = outputArgsSize;

    /* Release the output arguments node */
    UA_NODESTORE_RELEASE(server, (const UA_Node*)outputArguments);

    /* Call the method. If this is an async method, unlock the server lock for
     * the duration of the (long-running) call. */
    return resolvedMethod->method(server, &session->sessionId, session->context,
                                  &resolvedMethod->head.nodeId,
                                  resolvedMethod->head.context,
                                  &callContext->head.nodeId, callContext->head.context,
                                  request->inputArgumentsSize, mutableInputArgs,
                                  result->outputArgumentsSize, result->outputArguments);

    /* TODO: Verify Output matches the argument definition */
}

static UA_StatusCode
callWithMethodAndObject(UA_Server *server, UA_Session *session,
                        const UA_CallMethodRequest *request,
                        UA_CallMethodResult *result,
                        const UA_Node *callMethod,
                        const UA_Node *callObject) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Verify the context object's NodeClass */
    if(callObject->head.nodeClass != UA_NODECLASS_OBJECT &&
       callObject->head.nodeClass != UA_NODECLASS_OBJECTTYPE)
        return UA_STATUSCODE_BADNODECLASSINVALID;

    /* Verify the method's NodeClass */
    if(callMethod->head.nodeClass != UA_NODECLASS_METHOD)
        return UA_STATUSCODE_BADNODECLASSINVALID;

    /* For object types the given method must be directly referenced!
     * OPC UA 1.05.06 will state in Part 4 - Call Service Parameters
     * the following for parameter "objectId":
     * "In case of an ObjectType the ObjectType shall be the source of a
     *  HasComponent Reference (or subtype of HasComponent Reference) to the
     *  Method specified in methodId" */

    /* Find the matching Method of the same BrowseName referenced directly by
     * the calling object */
    UA_NodeId resolvedMethodId;
    UA_StatusCode res =
        findChildByBrowsename(server, session, callObject->head.nodeId,
                              UA_NODECLASS_METHOD, UA_REFERENCETYPEINDEX_HASCOMPONENT,
                              UA_NS0ID(HASCOMPONENT), &callMethod->head.browseName,
                              &resolvedMethodId);
    if(res != UA_STATUSCODE_GOOD)
        return (res == UA_STATUSCODE_BADNOTFOUND) ?
            UA_STATUSCODE_BADMETHODINVALID : res;

    /* The resolved methodId is different */
    const UA_MethodNode *resolvedMethod = (const UA_MethodNode*)callMethod;
    if(!UA_NodeId_equal(&resolvedMethodId, &callMethod->head.nodeId)) {
        /* Check whether the original MethodId comes from an ObjectType that is
         * upwards in the type hierarchy. Downwards in the type hierarchy (or
         * even completely unrelated) is not allowed. */
        res = checkMethodInTypeHierarchy(server, session,
                                         &callObject->head.nodeId,
                                         &callMethod->head.nodeId,
                                         &callMethod->head.browseName);
        if(res != UA_STATUSCODE_GOOD) {
            if(res == UA_STATUSCODE_BADNOTFOUND)
                res = UA_STATUSCODE_BADMETHODINVALID;
            goto errout;
        }

        /* Get the resolved method node */
        resolvedMethod = (const UA_MethodNode*)
            UA_NODESTORE_GET_SELECTIVE(server, &resolvedMethodId,
                                       UA_NODEATTRIBUTESMASK_NODECLASS |
                                       UA_NODEATTRIBUTESMASK_EXECUTABLE,
                                       UA_REFERENCETYPESET_NONE,
                                       UA_BROWSEDIRECTION_INVALID);
        if(!resolvedMethod) {
            res = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    /* Run the main call logic */
    res = callWithResolvedMethodAndObject(server, session, request, result,
                                          resolvedMethod, callObject);

 errout:
    /* Release the resolved method node if it is different */
    if(resolvedMethod && (const UA_Node*)resolvedMethod != callMethod)
        UA_NODESTORE_RELEASE(server, (const UA_Node*)resolvedMethod);
    UA_NodeId_clear(&resolvedMethodId);
    return res;
}

UA_Boolean
Operation_CallMethod(UA_Server *server, UA_Session *session,
                     const UA_CallMethodRequest *request,
                     UA_CallMethodResult *result) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get the method node. We only need the nodeClass and browseName
     * attribute. */
    const UA_Node *method =
        UA_NODESTORE_GET_SELECTIVE(server, &request->methodId,
                                   UA_NODEATTRIBUTESMASK_NODECLASS |
                                   UA_NODEATTRIBUTESMASK_BROWSENAME,
                                   UA_REFERENCETYPESET_NONE,
                                   UA_BROWSEDIRECTION_INVALID);
    if(!method) {
        result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
        return true;
    }

    /* Get the object node. We only need the NodeClass attribute. But take all
     * references for now.
     *
     * TODO: Which references do we need actually? */
    const UA_Node *object =
        UA_NODESTORE_GET_SELECTIVE(server, &request->objectId,
                                   UA_NODEATTRIBUTESMASK_NODECLASS,
                                   UA_REFERENCETYPESET_ALL,
                                   UA_BROWSEDIRECTION_BOTH);
    if(!object) {
        result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
        UA_NODESTORE_RELEASE(server, method);
        return true;
    }

    /* Continue with method and object (which can be an ObjectType) as
     * context */
    result->statusCode =
        callWithMethodAndObject(server, session, request,
                                result, method, object);

    /* Release the method and object node */
    UA_NODESTORE_RELEASE(server, method);
    UA_NODESTORE_RELEASE(server, object);

    return (result->statusCode != UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY);
}

UA_CallMethodResult
UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) {
    UA_CallMethodResult result;
    UA_CallMethodResult_init(&result);
    lockServer(server);
    Operation_CallMethod(server, &server->adminSession, request, &result);
    /* Cancel asynchronous responses right away */
    if(result.statusCode == UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY) {
        if(server->config.asyncOperationCancelCallback)
            server->config.asyncOperationCancelCallback(server, result.outputArguments);
        result.statusCode = UA_STATUSCODE_BADWAITINGFORRESPONSE;
    }
    unlockServer(server);
    return result;
}

#endif /* UA_ENABLE_METHODCALLS */

/**** amalgamated original file "/src/server/ua_services_session.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2018-2020 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2025 (c) Siemens AG (Author: Tin Raic)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


void
notifySession(UA_Server *server, UA_Session *session,
              UA_ApplicationNotificationType type) {
    /* Nothing to do */
    if(!server->config.globalNotificationCallback &&
       !server->config.sessionNotificationCallback)
        return;

    /* Set up the payload */
    size_t payloadSize = 6 + session->attributes.mapSize;
    UA_STACKARRAY(UA_KeyValuePair, payloadData, payloadSize);
    UA_KeyValueMap payloadMap = {payloadSize, payloadData};
    payloadData[0].key = UA_QUALIFIEDNAME(0, "session-id");
    UA_Variant_setScalar(&payloadData[0].value, &session->sessionId,
                         &UA_TYPES[UA_TYPES_NODEID]);
    payloadData[1].key = UA_QUALIFIEDNAME(0, "securechannel-id");
    UA_UInt32 secureChannelId = 0;
    if(session->channel)
        secureChannelId = session->channel->securityToken.channelId;
    UA_Variant_setScalar(&payloadData[1].value, &secureChannelId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    payloadData[2].key = UA_QUALIFIEDNAME(0, "session-name");
    UA_Variant_setScalar(&payloadData[2].value, &session->sessionName,
                         &UA_TYPES[UA_TYPES_STRING]);
    payloadData[3].key = UA_QUALIFIEDNAME(0, "client-description");
    UA_Variant_setScalar(&payloadData[3].value, &session->clientDescription,
                         &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
    payloadData[4].key = UA_QUALIFIEDNAME(0, "client-user-id");
    UA_Variant_setScalar(&payloadData[4].value, &session->clientUserIdOfSession,
                         &UA_TYPES[UA_TYPES_STRING]);
    payloadData[5].key = UA_QUALIFIEDNAME(0, "locale-ids");
    UA_Variant_setArray(&payloadData[5].value, session->localeIds,
                        session->localeIdsSize, &UA_TYPES[UA_TYPES_STRING]);

    if(session->attributes.mapSize)
        memcpy(&payloadData[6], session->attributes.map,
               sizeof(UA_KeyValuePair) * session->attributes.mapSize);

    /* Call the notification callback */
    if(server->config.sessionNotificationCallback)
        server->config.sessionNotificationCallback(server, type, payloadMap);
    if(server->config.globalNotificationCallback)
        server->config.globalNotificationCallback(server, type, payloadMap);
}

/* Delayed callback to free the session memory */
static void
removeSessionCallback(UA_Server *server, session_list_entry *entry) {
    lockServer(server);
    UA_Session_clear(&entry->session, server);
    unlockServer(server);
    UA_free(entry);
}

void
UA_Session_remove(UA_Server *server, UA_Session *session,
                  UA_ShutdownReason shutdownReason) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* When the session times out, detach
     * subscriptions so they can be recovered via TransferSubscriptions. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_Subscription *sub, *tempsub;
    TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, tempsub) {
        if(shutdownReason == UA_SHUTDOWNREASON_TIMEOUT) {
            UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                                     "Detaching the Subscription from the timed-out Session");
            UA_Session_detachSubscription(server, session, sub, true);
        } else {
            UA_Subscription_delete(server, sub);
        }
    }

    UA_PublishResponseEntry *entry;
    while((entry = UA_Session_dequeuePublishReq(session))) {
        UA_PublishResponse_clear(&entry->response);
        UA_free(entry);
    }
#endif

    /* Callback into userland access control */
    if(server->config.accessControl.closeSession) {
        server->config.accessControl.
            closeSession(server, &server->config.accessControl,
                         &session->sessionId, session->context);
    }

    /* Detach the Session from the SecureChannel */
    UA_Session_detachFromSecureChannel(server, session);

    /* Deactivate the session */
    if(session->activated) {
        session->activated = false;
        server->activeSessionCount--;
    }

    /* Detach the session from the session manager and make the capacity
     * available */
    session_list_entry *sentry = container_of(session, session_list_entry, session);
    LIST_REMOVE(sentry, pointers);
    server->sessionCount--;

    switch(shutdownReason) {
    case UA_SHUTDOWNREASON_CLOSE:
    case UA_SHUTDOWNREASON_PURGE:
        break;
    case UA_SHUTDOWNREASON_TIMEOUT:
        server->serverDiagnosticsSummary.sessionTimeoutCount++;
        break;
    case UA_SHUTDOWNREASON_REJECT:
        server->serverDiagnosticsSummary.rejectedSessionCount++;
        break;
    case UA_SHUTDOWNREASON_SECURITYREJECT:
        server->serverDiagnosticsSummary.securityRejectedSessionCount++;
        break;
    case UA_SHUTDOWNREASON_ABORT:
        server->serverDiagnosticsSummary.sessionAbortCount++;
        break;
    default:
        UA_assert(false);
        break;
    }

    /* Notify the application */
    notifySession(server, session, UA_APPLICATIONNOTIFICATIONTYPE_SESSION_CLOSED);

    /* Add a delayed callback to remove the session when the currently
     * scheduled jobs have completed */
    sentry->cleanupCallback.callback = (UA_Callback)removeSessionCallback;
    sentry->cleanupCallback.application = server;
    sentry->cleanupCallback.context = sentry;
    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, &sentry->cleanupCallback);
}

void
cleanupSessions(UA_Server *server, UA_DateTime nowMonotonic) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    session_list_entry *sentry, *temp;
    LIST_FOREACH_SAFE(sentry, &server->sessions, pointers, temp) {
        /* Session has timed out? */
        if(sentry->session.validTill >= nowMonotonic)
            continue;
        UA_LOG_INFO_SESSION(server->config.logging, &sentry->session,
                            "Session has timed out");
        UA_Session_remove(server, &sentry->session, UA_SHUTDOWNREASON_TIMEOUT);
    }
}

/************/
/* Services */
/************/

UA_Session *
getSessionByToken(UA_Server *server, const UA_NodeId *token) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    session_list_entry *current = NULL;
    LIST_FOREACH(current, &server->sessions, pointers) {
        /* Token does not match */
        if(!UA_NodeId_equal(&current->session.authenticationToken, token))
            continue;

        /* Session has timed out */
        UA_EventLoop *el = server->config.eventLoop;
        UA_DateTime now = el->dateTime_nowMonotonic(el);
        if(now > current->session.validTill) {
            UA_LOG_WARNING_SESSION(server->config.logging, &current->session,
                                   "Client tries to use a session that has timed out");
            return NULL;
        }

        return &current->session;
    }

    return NULL;
}

UA_Session *
getSessionById(UA_Server *server, const UA_NodeId *sessionId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    session_list_entry *current = NULL;
    LIST_FOREACH(current, &server->sessions, pointers) {
        /* Token does not match */
        if(!UA_NodeId_equal(&current->session.sessionId, sessionId))
            continue;

        /* Session has timed out */
        UA_EventLoop *el = server->config.eventLoop;
        UA_DateTime now = el->dateTime_nowMonotonic(el);
        if(now > current->session.validTill) {
            UA_LOG_WARNING_SESSION(server->config.logging, &current->session,
                                   "Client tries to use a session that has timed out");
            return NULL;
        }

        return &current->session;
    }

    if(UA_NodeId_equal(sessionId, &server->adminSession.sessionId))
        return &server->adminSession;

    return NULL;
}

static UA_StatusCode
signCreateSessionResponse(UA_Server *server, UA_SecureChannel *channel,
                          const UA_CreateSessionRequest *request,
                          UA_CreateSessionResponse *response) {
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    const UA_SecurityPolicy *sp = channel->securityPolicy;
    void *cc = channel->channelContext;
    UA_SignatureData *signatureData = &response->serverSignature;

    /* Prepare the signature */
    const UA_SecurityPolicySignatureAlgorithm *signAlg = &sp->asymSignatureAlgorithm;
    size_t signatureSize = signAlg->getLocalSignatureSize(sp, cc);
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    /* OPC UA Part 4 v1.05.07: for SecurityPolicies with
     * secureChannelEnhancements = true, the algorithm field in
     * SignatureData shall be NULL or empty and receivers shall
     * ignore the value. */
    if(!UA_SecurityPolicy_isEnhancedSecurity(sp))
        retval = UA_String_copy(&signAlg->uri, &signatureData->algorithm);
    retval |= UA_ByteString_allocBuffer(&signatureData->signature, signatureSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Build the data to sign. */
    UA_ByteString dataToSign = UA_BYTESTRING_NULL;
    if(UA_SecurityPolicy_isEnhancedSecurity(sp)) {
        /* Channel-bound v1.05.07 signature (see the cert-role table at
         * UA_SecureChannel_buildCreateSessionSignatureData). */
        retval = UA_SecureChannel_buildCreateSessionSignatureData(
            channel, &request->clientNonce, &response->serverNonce,
            &sp->localCertificate, &channel->remoteCertificate, &dataToSign);
    } else {
        retval = UA_ByteString_allocBuffer(&dataToSign,
            request->clientCertificate.length + request->clientNonce.length);
        if(retval == UA_STATUSCODE_GOOD) {
            memcpy(dataToSign.data, request->clientCertificate.data,
                   request->clientCertificate.length);
            memcpy(dataToSign.data + request->clientCertificate.length,
                   request->clientNonce.data, request->clientNonce.length);
        }
    }
    if(retval != UA_STATUSCODE_GOOD)
        return retval; /* signatureData->signature is cleaned up with the response */

    retval = signAlg->sign(sp, cc, &dataToSign, &signatureData->signature);

    /* Clean up */
    UA_ByteString_clear(&dataToSign);
    return retval;
}

static UA_StatusCode
createCheckSessionAuthSecurityPolicyContext(UA_Server *server, UA_Session *session,
                                            UA_SecurityPolicy *sp, const char *logPrefix,
                                            const UA_ByteString remoteCertificate) {
    /* The session is already "taken" by a different SecurityPolicy */
    if(session->sessionSp && session->sessionSp != sp) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "%s: Cannot instantiate SecurityPolicyContext %S for the "
                             "Session. A different SecurityPolicy %S is "
                             "already in place", logPrefix, sp->policyUri,
                             session->sessionSp->policyUri);
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    }
    session->sessionSp = sp;

    /* Existing SecurityPolicy context, check for the identical remote
     * certificate */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(session->sessionSpContext) {
        res = sp->compareCertificate(sp, session->sessionSpContext, &remoteCertificate);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_SESSION(server->config.logging, session,
                                 "%s: The client tries to use a different certificate "
                                 "for authentication", logPrefix);
        }
        return res;
    }

    /* Instantiate a new context if we can. Otherwise operate without a channel
     * context. That is possible for asymmetric decryption with RSA which
     * requires only the local certificate. But ECC won't work. */
    if(remoteCertificate.length > 0) {
        res = sp->newChannelContext(sp, &remoteCertificate,
                                    &session->sessionSpContext);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_SESSION(server->config.logging, session,
                                 "%s: Could not use the supplied certificate "
                                 "to instantiate the SecurityPolicy %S for the "
                                 "validation of the UserIdentityToken",
                                 logPrefix, sp->policyUri);
        }
    }
    return res;
}

/* The client requests a server ephemeral ECDH key by adding an "ECDHPolicyUri"
 * entry to the request's AdditionalHeader (an AdditionalParametersType). The
 * server must return its ECDHKey only when this was requested. */
static UA_Boolean
clientRequestedEphemeralKey(const UA_ExtensionObject *additionalHeader) {
    if(additionalHeader->encoding != UA_EXTENSIONOBJECT_DECODED &&
       additionalHeader->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
        return false;
    if(additionalHeader->content.decoded.type !=
       &UA_TYPES[UA_TYPES_ADDITIONALPARAMETERSTYPE])
        return false;
    const UA_AdditionalParametersType *ap = (const UA_AdditionalParametersType*)
        additionalHeader->content.decoded.data;
    UA_String ecdhPolicyUri = UA_STRING("ECDHPolicyUri");
    for(size_t i = 0; i < ap->parametersSize; i++) {
        if(ap->parameters[i].key.namespaceIndex == 0 &&
           UA_String_equal(&ap->parameters[i].key.name, &ecdhPolicyUri))
            return true;
    }
    return false;
}

static UA_StatusCode
addEphemeralKeyAdditionalHeader(UA_Server *server, UA_Session *session,
                                UA_ExtensionObject *ah) {
    UA_assert(session->sessionSp && session->sessionSpContext);
    UA_SecurityPolicy *sp = session->sessionSp;
    void *spContext = session->sessionSpContext;

    /* Allocate additional parameters */
    UA_AdditionalParametersType *ap = UA_AdditionalParametersType_new();
    if(!ap)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set the additional parameters in the additional header. They also get
     * cleaned up from there in the error case. */
    UA_ExtensionObject_setValue(ah, ap, &UA_TYPES[UA_TYPES_ADDITIONALPARAMETERSTYPE]);

    /* UA_KeyValueMap has the identical layout. And better helper methods. */
    UA_KeyValueMap *map = (UA_KeyValueMap*)ap;

    /* Add the PolicyUri to the map */
    UA_StatusCode res =
        UA_KeyValueMap_setScalar(map, UA_QUALIFIEDNAME(0, "ECDHPolicyUri"),
                                 &sp->policyUri, &UA_TYPES[UA_TYPES_STRING]);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Initialize the EphemeralKey on the stack */
    UA_EphemeralKeyType ephKey;
    UA_EphemeralKeyType_init(&ephKey);

    /* Allocate the ephemeral key buffer to the exact size of the ephemeral key
     * for the used ECC policy so that the nonce generation function knows that
     * it needs to generate an ephemeral key and not some other random byte
     * string.
     *
     * TODO: There should be a more stable way to signal the generation of an
     * ephemeral key */
    res = UA_ByteString_allocBuffer(&ephKey.publicKey, sp->nonceLength);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Allocate the signature buffer */
    size_t signatureSize =
        sp->asymSignatureAlgorithm.getLocalSignatureSize(sp, spContext);
    res = UA_ByteString_allocBuffer(&ephKey.signature, signatureSize);
    if(res != UA_STATUSCODE_GOOD) {
        UA_EphemeralKeyType_clear(&ephKey);
        return res;
    }

    /* Generate the ephemeral key and signature */
    ephKey.publicKey.data[0] = 'e';
    ephKey.publicKey.data[1] = 'p';
    ephKey.publicKey.data[2] = 'h';
    res |= sp->generateNonce(sp, spContext, &ephKey.publicKey);
    res |= sp->asymSignatureAlgorithm.sign(sp, spContext, &ephKey.publicKey,
                                           &ephKey.signature);

    /* Add the EphemeralKey to the map (deep copy) */
    if(res == UA_STATUSCODE_GOOD)
        res = UA_KeyValueMap_setScalar(map, UA_QUALIFIEDNAME(0, "ECDHKey"),
                                       &ephKey, &UA_TYPES[UA_TYPES_EPHEMERALKEYTYPE]);
    UA_EphemeralKeyType_clear(&ephKey);
    return res;
}

/* Creates and adds a session. But it is not yet attached to a secure channel. */
UA_StatusCode
UA_Session_create(UA_Server *server, UA_SecureChannel *channel,
                  const UA_CreateSessionRequest *request, UA_Session **session) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->sessionCount >= server->config.maxSessions) {
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "CreateSession: Could not create a Session - "
                             "Server limits reached");
        return UA_STATUSCODE_BADTOOMANYSESSIONS;
    }

    session_list_entry *newentry = (session_list_entry*)
        UA_malloc(sizeof(session_list_entry));
    if(!newentry)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Initialize the Session */
    UA_Session_init(&newentry->session);
    newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random());
    newentry->session.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());

    newentry->session.timeout = server->config.maxSessionTimeout;
    if(request->requestedSessionTimeout <= server->config.maxSessionTimeout &&
       request->requestedSessionTimeout > 0)
        newentry->session.timeout = request->requestedSessionTimeout;

    /* Attach the session to the channel. But don't activate for now. */
    if(channel)
        UA_Session_attachToSecureChannel(server, &newentry->session, channel);

    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime now = el->dateTime_now(el);
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_Session_updateLifetime(&newentry->session, now, nowMonotonic);

    /* Add to the server */
    LIST_INSERT_HEAD(&server->sessions, newentry, pointers);
    server->sessionCount++;

    /* Notify the application */
    notifySession(server, &newentry->session,
                  UA_APPLICATIONNOTIFICATIONTYPE_SESSION_CREATED);

    /* Return */
    *session = &newentry->session;
    return UA_STATUSCODE_GOOD;
}

void
Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                      const UA_CreateSessionRequest *request,
                      UA_CreateSessionResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_LOG_DEBUG_CHANNEL(server->config.logging, channel, "CreateSession");

    void *cc = channel->channelContext;
    UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_ResponseHeader *rh = &response->responseHeader;
    UA_assert(sp != NULL);

    /* Part 4: In many cases, the Certificates used to establish the
     * SecureChannel will be the ApplicationInstanceCertificates. However, some
     * Communication Stacks might not support Certificates that are specific to
     * a single application. Instead, they expect all communication to be
     * secured with a Certificate specific to a user or the entire machine. For
     * this reason, OPC UA Applications will need to exchange their
     * ApplicationInstanceCertificates when creating a Session.
     *
     * However Part 6 requires that the asymmetric algorithm security header
     * contains the "X.509 v3 Certificate assigned to the sending application
     * Instance." So we assume that the SecureChannel was created with the same
     * ApplicationInstanceCertificate. This may change in the future for
     * additional transport types. */
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {

        /* Compare the clientCertificate with the remoteCertificate of the
         * channel.
         *
         * Both the clientCertificate of this request and the remoteCertificate
         * of the channel may contain a partial or a complete certificate chain.
         * The compareCertificate function will compare the first certificate of
         * each chain. The end certificate shall be located first in the chain
         * according to the OPC UA specification Part 6 (1.04), chapter 6.2.3.*/
        UA_StatusCode res = sp->compareCertificate(sp, cc, &request->clientCertificate);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                                 "CreateSession: The client uses a different "
                                 "certificate for SecureChannel and Session");
            server->serverDiagnosticsSummary.securityRejectedSessionCount++;
            server->serverDiagnosticsSummary.rejectedSessionCount++;
            rh->serviceResult = UA_STATUSCODE_BADCERTIFICATEINVALID;
            return;
        }
    }

    /* Check the client certificate and ApplicationDescription. It was already
     * checked for the SecureChannel. But here we use the Session
     * CertificateGroup and we now also have the ApplicationDescription to check
     * the ApplicationUri.
     *
     * Per OPC UA Part 4, Section 5.6.2.2: "If the securityPolicyUri is None,
     * the Server shall ignore the ApplicationInstanceCertificate." */
    if(channel->securityPolicy->policyType == UA_SECURITYPOLICYTYPE_NONE) {
        if(request->clientCertificate.length > 0) {
            UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                                   "CreateSession: Ignoring client certificate "
                                   "on SecurityPolicy None (Part 4, 5.6.2.2)");
        }
    } else if(request->clientCertificate.length > 0) {
        rh->serviceResult =
            validateCertificate(server, &server->config.secureChannelPKI,
                                channel, NULL, "CreateSession",
                                &request->clientDescription,
                                request->clientCertificate);
        if(rh->serviceResult != UA_STATUSCODE_GOOD) {
            server->serverDiagnosticsSummary.securityRejectedSessionCount++;
            server->serverDiagnosticsSummary.rejectedSessionCount++;
            return;
        }
    }

    /* According to the spec, the (session) ClientNonce needs a length between
     * 32 and 128 bytes inclusive. This is the application nonce length and is
     * independent of the SecurityPolicy's SecureChannel nonce length (for ECC
     * policies that is the 64-byte ephemeral key, which is NOT the session
     * nonce). */
    if(channel->securityPolicy->policyType != UA_SECURITYPOLICYTYPE_NONE &&
       (request->clientNonce.length < 32 || request->clientNonce.length > 128)) {
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "CreateSession: The nonce provided by the client "
                             "has the wrong length");
        server->serverDiagnosticsSummary.securityRejectedSessionCount++;
        server->serverDiagnosticsSummary.rejectedSessionCount++;
        rh->serviceResult = UA_STATUSCODE_BADNONCEINVALID;
        return;
    }

    /* Create the Session */
    UA_Session *newSession = NULL;
    rh->serviceResult = UA_Session_create(server, channel, request, &newSession);
    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        server->serverDiagnosticsSummary.rejectedSessionCount++;
        return;
    }

    /* If the session name is empty, use the generated SessionId */
    rh->serviceResult |= UA_String_copy(&request->sessionName,
                                        &newSession->sessionName);
    if(newSession->sessionName.length == 0)
        rh->serviceResult |= UA_NodeId_print(&newSession->sessionId,
                                             &newSession->sessionName);

    /* Configure the Session */
    newSession->maxResponseMessageSize = request->maxResponseMessageSize;
    newSession->maxRequestMessageSize = channel->config.localMaxMessageSize;
    rh->serviceResult |= UA_ApplicationDescription_copy(&request->clientDescription,
                                                        &newSession->clientDescription);

    /* The SecureChannel certificate must correspond to the client's
     * ApplicationCertificate. But for unencrypted SecureChannels we store the
     * certificate directly in the Session. We need it later when an encrypted
     * UserIdentityToken is sent over an unencrypted SecureChannel. */
    if(channel->remoteCertificate.length == 0)
        rh->serviceResult |= UA_ByteString_copy(&request->clientCertificate,
                                                &newSession->clientCertificate);

    /* Retain the clientNonce for the v1.05.07 channel-bound
     * ActivateSession ClientSignature verification
     * (secureChannelEnhancements). */
    rh->serviceResult |= UA_ByteString_copy(&request->clientNonce,
                                            &newSession->clientNonce);

#ifdef UA_ENABLE_DIAGNOSTICS
    rh->serviceResult |= UA_String_copy(&request->serverUri,
                                        &newSession->diagnostics.serverUri);
    rh->serviceResult |= UA_String_copy(&request->endpointUrl,
                                        &newSession->diagnostics.endpointUrl);
#endif

    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "CreateSession: Could not create new session (%s)",
                             UA_StatusCode_name(rh->serviceResult));
        UA_Session_remove(server, newSession, UA_SHUTDOWNREASON_REJECT);
        return;
    }

    /* Get the SecurityPolicy for UserToken encryption and instantiate it. The
     * same selection is done for the local endpoints in
     * updateEndpointUserIdentityToken. Don't mix RSA/ECC between channel and
     * authentication. */
    UA_SecurityPolicy *sessionSp = NULL;
    if(request->clientCertificate.length > 0) {
        if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
            sessionSp = getDefaultEncryptedSecurityPolicy(server, sp->policyType);
        else
            sessionSp = sp;
    }
    if(sessionSp) {
        rh->serviceResult =
            createCheckSessionAuthSecurityPolicyContext(server, newSession,
                                                        sessionSp, "CreateSession",
                                                        request->clientCertificate);
        if(rh->serviceResult != UA_STATUSCODE_GOOD) {
            UA_Session_remove(server, newSession, UA_SHUTDOWNREASON_REJECT);
            return;
        }
    }

    /* Generate the nonce. This uses the session-SecurityPolicy if defined.
     * Otherwise the SecurityPolicy of the SecureChannel. */
    rh->serviceResult = UA_Session_generateNonce(newSession);
    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "CreateSession: Could not create the server nonce (%s)",
                             UA_StatusCode_name(rh->serviceResult));
        UA_Session_remove(server, newSession, UA_SHUTDOWNREASON_REJECT);
        return;
    }

    /* If an ECC policy, create an ephemeral key to be returned in the response.
     * The private part of the ephemeral key is persisted in the
     * Session-SecurityPolicy context. Until it gets overridden during
     * ActivateSession. */
    if(sessionSp && UA_SecurityPolicy_isEcc(sessionSp) &&
       clientRequestedEphemeralKey(&request->requestHeader.additionalHeader)) {
        rh->serviceResult = addEphemeralKeyAdditionalHeader(server, newSession,
                                                            &rh->additionalHeader);
        if(rh->serviceResult != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                                 "CreateSession: Could not prepare the ephemeral key (%s)",
                                 UA_StatusCode_name(rh->serviceResult));
            UA_Session_remove(server, newSession, UA_SHUTDOWNREASON_REJECT);
            return;
        }
    }

    /* Prepare the response */
    response->sessionId = newSession->sessionId;
    response->revisedSessionTimeout = (UA_Double)newSession->timeout;
    response->authenticationToken = newSession->authenticationToken;
    rh->serviceResult |= UA_ByteString_copy(&newSession->serverNonce,
                                            &response->serverNonce);
    /* The CreateSessionResponse carries the Server's application instance
     * certificate so the Client can encrypt the UserIdentityToken with it. This
     * is needed even on a #None SecureChannel when the user token is encrypted
     * "on top" (sessionSp is then the user-token encryption policy, whose
     * localCertificate is the Server certificate; the #None channel policy has
     * no certificate). So copy it whenever a session-auth SecurityPolicy was
     * instantiated, regardless of the channel SecurityMode. */
    if(sessionSp)
        rh->serviceResult |= UA_ByteString_copy(&sessionSp->localCertificate,
                                                &response->serverCertificate);

    /* Copy the server's endpointdescriptions into the response */
    rh->serviceResult |= setCurrentEndpointsArray(server, request->endpointUrl,
                                                  NULL, 0,
                                                  &response->serverEndpoints,
                                                  &response->serverEndpointsSize);

    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "CreateSession: Could not prepare the response (%s)",
                             UA_StatusCode_name(rh->serviceResult));
        UA_Session_remove(server, newSession, UA_SHUTDOWNREASON_REJECT);
        return;
    }

    /* Sign the signature */
    rh->serviceResult |=
        signCreateSessionResponse(server, channel, request, response);
    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        UA_Session_remove(server, newSession, UA_SHUTDOWNREASON_REJECT);
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "CreateSession: Could not sign the response (%s)",
                             UA_StatusCode_name(rh->serviceResult));
        return;
    }

#ifdef UA_ENABLE_DIAGNOSTICS
    UA_EventLoop *el = server->config.eventLoop;
    newSession->diagnostics.clientConnectionTime = el->dateTime_now(el);
    newSession->diagnostics.clientLastContactTime =
        newSession->diagnostics.clientConnectionTime;

    /* Create the object in the information model */
    createSessionObject(server, newSession);
#endif

    UA_LOG_INFO_SESSION(server->config.logging, newSession, "Session created");
}

static UA_StatusCode
checkCertificateSignature(const UA_Server *server, const UA_SecurityPolicy *tokenSp,
                          void *channelContext, const UA_ByteString *serverNonce,
                          const UA_SignatureData *signature,
                          const bool isUserTokenSignature, bool allowEmptyLocalCert) {
    UA_assert(tokenSp != NULL);

    /* Check for zero signature length */
    if(signature->signature.length == 0) {
        if(isUserTokenSignature)
            return UA_STATUSCODE_BADUSERSIGNATUREINVALID;
        return UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID;
    }

    /* Data to verify is calculated by appending the serverNonce to the local
     * certificate */
    const UA_ByteString *localCertificate = &tokenSp->localCertificate;
    UA_ByteString dataToVerify;
    size_t dataToVerifySize = localCertificate->length + serverNonce->length;
    UA_StatusCode res = UA_ByteString_allocBuffer(&dataToVerify, dataToVerifySize);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    memcpy(dataToVerify.data, localCertificate->data, localCertificate->length);
    memcpy(dataToVerify.data + localCertificate->length, serverNonce->data, serverNonce->length);

 check_certificate:
    res = tokenSp->asymSignatureAlgorithm.
        verify(tokenSp, channelContext, &dataToVerify, &signature->signature);
    if(res != UA_STATUSCODE_GOOD) {
        if(isUserTokenSignature)
            res = UA_STATUSCODE_BADUSERSIGNATUREINVALID;
        else
            res = UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID;
    }

    if(dataToVerify.data != serverNonce->data)
        UA_ByteString_clear(&dataToVerify);

    /* Workaround: If the SecureChannel is #None, the client might have used the
     * ApplicationInstanceCertificate of the server (maybe it was in the
     * EndpointDescription) or not. If the MessageSecurityMode is #None, then
     * retry with an empty server certificate. */
    if(res != UA_STATUSCODE_GOOD && localCertificate->length > 0 && allowEmptyLocalCert) {
        localCertificate = &UA_BYTESTRING_NULL;
        dataToVerify = *serverNonce;
        goto check_certificate;
    }

    return res;
}

/* Always sets tokenSp (default: SecurityPolicy of the channel) */
static const UA_UserTokenPolicy *
selectTokenPolicy(UA_Server *server, UA_SecureChannel *channel,
                  UA_Session *session, const UA_ExtensionObject *identityToken,
                  const UA_EndpointDescription *ed,
                  UA_SecurityPolicy **tokenSp) {
    /* If no UserTokenPolicies are configured in the endpoint, then use
     * those configured in the AccessControl plugin. */
    size_t identPoliciesSize = ed->userIdentityTokensSize;
    const UA_UserTokenPolicy *identPolicies = ed->userIdentityTokens;
    if(identPoliciesSize == 0) {
        identPoliciesSize = server->config.accessControl.userTokenPoliciesSize;
        identPolicies = server->config.accessControl.userTokenPolicies;
    }

    /* Match the UserTokenType */
    const UA_DataType *tokenDataType = identityToken->content.decoded.type;
    for(size_t j = 0; j < identPoliciesSize; j++) {
        const UA_UserTokenPolicy *pol = &identPolicies[j];

        /* Part 4, Section 5.6.3.2, Table 17: A NULL or empty
         * UserIdentityToken should be treated as Anonymous */
        if(identityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY &&
           pol->tokenType == UA_USERTOKENTYPE_ANONYMOUS) {
            *tokenSp = channel->securityPolicy;
            return pol;
        }

        /* Expect decoded content if not anonymous */
        if(!tokenDataType)
            continue;

        /* Match the DataType of the provided token with the policy */
        switch(pol->tokenType) {
        case UA_USERTOKENTYPE_ANONYMOUS:
            if(tokenDataType != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN])
                continue;
            break;
        case UA_USERTOKENTYPE_USERNAME:
            if(tokenDataType != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])
                continue;
            break;
        case UA_USERTOKENTYPE_CERTIFICATE:
            if(tokenDataType != &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN])
                continue;
            break;
        case UA_USERTOKENTYPE_ISSUEDTOKEN:
            if(tokenDataType != &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN])
                continue;
            break;
        default:
            continue;
        }

        /* All valid token data types start with a string policyId. Casting
         * to anonymous hence works for all of them. */
        UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*)
            identityToken->content.decoded.data;

        /* In setCurrentEndpointsArray we prepend the PolicyId with the
         * SecurityMode of the endpoint and the postfix of the
         * SecurityPolicyUri to make it unique. Check the PolicyId. */
        if(pol->policyId.length > token->policyId.length)
            continue;
        UA_String policyPrefix = token->policyId;
        policyPrefix.length = pol->policyId.length;
        if(!UA_String_equal(&policyPrefix, &pol->policyId))
            continue;

        /* Get the SecurityPolicy for the endpoint from the postfix */
        UA_String utPolPostfix = securityPolicyUriPostfix(token->policyId);
        UA_SecurityPolicy *candidateSp =
            getSecurityPolicyByPostfix(server, utPolPostfix);
        if(!candidateSp) {
            UA_LOG_WARNING_SESSION(server->config.logging, session,
                                   "ActivateSession: The UserTokenPolicy of "
                                   "the endpoint defines an unknown "
                                   "SecurityPolicy %S",
                                   pol->securityPolicyUri);
            continue;
        }

        /* A non-anonymous authentication token is transmitted over an
         * unencrypted SecureChannel */
        if(pol->tokenType != UA_USERTOKENTYPE_ANONYMOUS &&
           channel->securityPolicy->policyType == UA_SECURITYPOLICYTYPE_NONE &&
           candidateSp->policyType == UA_SECURITYPOLICYTYPE_NONE) {
            /* Check if the allowNonePolicyPassword option is set.
             * But this exception only works for Username/Password. */
            if(!server->config.allowNonePolicyPassword ||
               pol->tokenType != UA_USERTOKENTYPE_USERNAME)
                continue;
        }

        /* Found a match policy */
        *tokenSp = candidateSp;
        return pol;
    }

    return NULL;
}

static void
selectEndpointAndTokenPolicy(UA_Server *server, UA_SecureChannel *channel,
                             UA_Session *session,
                             const UA_ExtensionObject *identityToken,
                             const UA_EndpointDescription **ed,
                             const UA_UserTokenPolicy **utp,
                             UA_SecurityPolicy **tokenSp) {
    UA_ServerConfig *sc = &server->config;
    for(size_t i = 0; i < sc->endpointsSize; ++i) {
        const UA_EndpointDescription *desc = &sc->endpoints[i];

        /* Match the Security Mode */
        if(desc->securityMode != channel->securityMode)
            continue;

        /* Match the SecurityPolicy of the endpoint with the current channel */
        if(!UA_String_equal(&desc->securityPolicyUri,
                            &channel->securityPolicy->policyUri))
            continue;

        /* Select the UserTokenPolicy from the Endpoint */
        *utp = selectTokenPolicy(server, channel, session,
                                 identityToken, desc, tokenSp);
        if(*utp) {
            /* Match found */
            *ed = desc;
            return;
        }
    }
}

static UA_StatusCode
hideX509IdentityTokenValidationStatus(UA_StatusCode status) {
    if(status == UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_GOOD;
    return UA_STATUSCODE_BADIDENTITYTOKENREJECTED;
}

static UA_StatusCode
checkActivateSessionX509(UA_Server *server, UA_SecureChannel *channel, UA_Session *session,
                         const UA_SecurityPolicy *tokenSp, UA_X509IdentityToken* token,
                         const UA_SignatureData *tokenSignature) {
    /* The SecurityPolicy must not be None for the signature */
    if(tokenSp->policyType == UA_SECURITYPOLICYTYPE_NONE)
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

    /* We need a channel context with the user certificate in order to reuse
     * the signature checking code. */
    void *tempChannelContext;
    UA_StatusCode res = tokenSp->newChannelContext(tokenSp, &token->certificateData,
                                                   &tempChannelContext);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: Failed to create a context "
                             "for the SecurityPolicy %S", tokenSp->policyUri);
        return res;
    }

    /* Check the user token signature. The channel-bound v1.05.07 layout (see
     * the cert-role table at UA_SecureChannel_buildUserTokenSignatureData) is
     * used only when BOTH the SecureChannel AND the user-token SecurityPolicy
     * are enhanced; a legacy RSA / old-ECC user token uses the legacy layout
     * even over an enhanced (AesGcm) SecureChannel. */
    if(UA_SecurityPolicy_isEnhancedSecurity(channel->securityPolicy) &&
       UA_SecurityPolicy_isEnhancedSecurity(tokenSp)) {
        if(tokenSignature->signature.length == 0) {
            res = UA_STATUSCODE_BADUSERSIGNATUREINVALID;
            goto out;
        }
        UA_ByteString dataToVerify = UA_BYTESTRING_NULL;
        res = UA_SecureChannel_buildUserTokenSignatureData(
            channel, &session->serverNonce, &session->clientNonce,
            &channel->securityPolicy->localCertificate,
            &channel->securityPolicy->localCertificate,
            &channel->remoteCertificate, &channel->remoteCertificate, &dataToVerify);
        if(res == UA_STATUSCODE_GOOD) {
            res = tokenSp->asymSignatureAlgorithm.verify(
                tokenSp, tempChannelContext, &dataToVerify, &tokenSignature->signature);
            if(res != UA_STATUSCODE_GOOD)
                res = UA_STATUSCODE_BADUSERSIGNATUREINVALID;
        }
        UA_ByteString_clear(&dataToVerify);
    } else {
        res = checkCertificateSignature(server, tokenSp, tempChannelContext, &session->serverNonce,
                                        tokenSignature, true,
                                        (channel->securityMode == UA_MESSAGESECURITYMODE_NONE));
    }
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: User token signature check "
                             "failed with StatusCode %s", UA_StatusCode_name(res));
        goto out;
    }

    /* Validate the certificate against the SessionPKI */
    res = validateCertificate(server, &server->config.sessionPKI,
                              session->channel, session, "ActivateSession",
                              NULL, token->certificateData);
    res = hideX509IdentityTokenValidationStatus(res);

 out:
    /* Delete the temporary channel context */
    tokenSp->deleteChannelContext(tokenSp, tempChannelContext);
    return res;
}

static UA_StatusCode
decryptUserToken(UA_Server *server, UA_Session *session, UA_SecureChannel *channel,
                 UA_SecurityPolicy *tokenSp, UA_ByteString *token,
                 const UA_String encryptionAlgorithm) {
    /* Not encrypted */
    if(tokenSp->policyType == UA_SECURITYPOLICYTYPE_NONE) {
        if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
            UA_LOG_WARNING_SESSION(server->config.logging, session,
                                   "ActivateSession: Processing an unencrypted "
                                   "UserToken. This is dangerous for the server "
                                   "to allow.");
        return UA_STATUSCODE_GOOD;
    }

    /* Test if the correct encryption algorithm is used. Note that some clients
     * don't set the EncryptionAlgorithmUri. Skip the check for those.*/
    if(encryptionAlgorithm.length > 0 &&
       !UA_String_equal(&tokenSp->asymEncryptionAlgorithm.uri,
                        &encryptionAlgorithm)) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: Encryption algorithm used "
                             "for the UserIdentityToken does not match "
                             "the endpoint");
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
    }

    /* Try to create an instance of the authentication SecurityPolicy to decrypt
     * the UserIdentityToken. For RSA-based async encryption we don't need that. */
    UA_ByteString applicationCert = (channel->remoteCertificate.length > 0) ?
        channel->remoteCertificate : session->clientCertificate;
    UA_StatusCode res =
        createCheckSessionAuthSecurityPolicyContext(server, session, tokenSp,
                                                    "ActivateSession", applicationCert);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Decrypt the token. Differentiate between secret encryptions (ECC,
     * legacy).
     * TODO: Implement "modern" RSA secret encryption */
    if(UA_SecurityPolicy_isEcc(tokenSp)) {
        res = decryptUserTokenEcc(server->config.logging, channel,
                                session->sessionSp, session->sessionSpContext,
                                session->serverNonce, token);
    } else {
        res = decryptSecretLegacy(session->sessionSp, session->sessionSpContext,
                                  session->serverNonce, token);
    }
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: Could not decrypt/"
                             "cryptographically validate the UserIdentityToken "
                             "with the StatusCode %s", UA_StatusCode_name(res));
    }
    return res;
}

/* TODO: Check all of the following: The Server shall verify that the
 * Certificate the Client used to create the new SecureChannel is the same as
 * the Certificate used to create the original SecureChannel. In addition, the
 * Server shall verify that the Client supplied a UserIdentityToken that is
 * identical to the token currently associated with the Session. Once the Server
 * accepts the new SecureChannel it shall reject requests sent via the old
 * SecureChannel. */

#define UA_SESSION_REJECT                                               \
    do {                                                                \
        server->serverDiagnosticsSummary.rejectedSessionCount++;        \
        return;                                                         \
    } while(0)

#define UA_SECURITY_REJECT                                              \
    do {                                                                \
        server->serverDiagnosticsSummary.securityRejectedSessionCount++; \
        server->serverDiagnosticsSummary.rejectedSessionCount++;        \
        return;                                                         \
    } while(0)

void
Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
                        const UA_ActivateSessionRequest *req,
                        UA_ActivateSessionResponse *resp) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_ResponseHeader *rh = &resp->responseHeader;

    /* Get the session */
    UA_Session *session =
        getSessionByToken(server, &req->requestHeader.authenticationToken);
    if(!session) {
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "ActivateSession: Session not found");
        rh->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
        UA_SESSION_REJECT;
    }

    /* Part 4, §5.6.3: When the ActivateSession Service is called for the
     * first time then the Server shall reject the request if the
     * SecureChannel is not same as the one associated with the
     * CreateSession request. Subsequent calls to ActivateSession may be
     * associated with different SecureChannels. */
    if(!session->activated && session->channel != channel) {
        UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                             "ActivateSession: The Session has to be initially "
                             "activated on the SecureChannel that created it");
        rh->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
        UA_SESSION_REJECT;
    }

    /* Has the session timed out? */
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    if(session->validTill < nowMonotonic) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: The Session has timed out");
        rh->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
        UA_SESSION_REJECT;
    }

    /* Check the client signature */
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        const UA_SecurityPolicy *csp = channel->securityPolicy;
        if(UA_SecurityPolicy_isEnhancedSecurity(csp)) {
            /* Channel-bound v1.05.07 ClientSignature (see the cert-role table at
             * UA_SecureChannel_buildActivateSessionSignatureData). clientNonce is
             * the ClientNonce stored at CreateSession. */
            if(req->clientSignature.signature.length == 0) {
                rh->serviceResult = UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID;
            } else {
                UA_ByteString dataToVerify = UA_BYTESTRING_NULL;
                rh->serviceResult = UA_SecureChannel_buildActivateSessionSignatureData(
                    channel, &session->serverNonce, &session->clientNonce,
                    &csp->localCertificate, &csp->localCertificate,
                    &channel->remoteCertificate, &dataToVerify);
                if(rh->serviceResult == UA_STATUSCODE_GOOD) {
                    rh->serviceResult = csp->asymSignatureAlgorithm.verify(
                        csp, channel->channelContext, &dataToVerify,
                        &req->clientSignature.signature);
                    if(rh->serviceResult != UA_STATUSCODE_GOOD)
                        rh->serviceResult = UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID;
                }
                UA_ByteString_clear(&dataToVerify);
            }
        } else {
            rh->serviceResult =
                checkCertificateSignature(server, channel->securityPolicy,
                                          channel->channelContext, &session->serverNonce,
                                          &req->clientSignature, false, false);
        }
        if(rh->serviceResult != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_SESSION(server->config.logging, session,
                                 "ActivateSession: Client signature check failed "
                                 "with StatusCode %s",
                                 UA_StatusCode_name(rh->serviceResult));
            UA_SECURITY_REJECT;
        }
    }

    /* Find the matching Endpoint with UserTokenPolicy.
     * Also sets the SecurityPolicy used to encrypt the token. */
    const UA_EndpointDescription *ed = NULL;
    const UA_UserTokenPolicy *utp = NULL;
    UA_SecurityPolicy *tokenSp = NULL;
    selectEndpointAndTokenPolicy(server, channel, session,
                                 &req->userIdentityToken,
                                 &ed, &utp, &tokenSp);
    if(!ed || !tokenSp) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: Requested Endpoint/UserTokenPolicy "
                             "not available");
        rh->serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        UA_SESSION_REJECT;
    }

    /* Decrypt (or validate the signature) of the UserToken. The DataType of the
     * UserToken was already checked in selectEndpointAndTokenPolicy. This
     * replaces the content of the token in-situ. */
    switch(utp->tokenType) {
    case UA_USERTOKENTYPE_ANONYMOUS:
        break;
    case UA_USERTOKENTYPE_USERNAME: {
        UA_UserNameIdentityToken *token = (UA_UserNameIdentityToken *)
           req->userIdentityToken.content.decoded.data;
        rh->serviceResult =
            decryptUserToken(server, session, channel, tokenSp,
                             &token->password, token->encryptionAlgorithm);
        break; }
    case UA_USERTOKENTYPE_CERTIFICATE: {
        /* Check the signature and verify the certificate in the sessionPKI */
        UA_X509IdentityToken* x509token = (UA_X509IdentityToken*)
            req->userIdentityToken.content.decoded.data;
        rh->serviceResult =
            checkActivateSessionX509(server, channel, session, tokenSp, x509token,
                                     &req->userTokenSignature);
        break; }
    case UA_USERTOKENTYPE_ISSUEDTOKEN: {
        UA_IssuedIdentityToken *token = (UA_IssuedIdentityToken*)
            req->userIdentityToken.content.decoded.data;
        rh->serviceResult =
            decryptUserToken(server, session, channel, tokenSp,
                             &token->tokenData, token->encryptionAlgorithm);
        break; }
    default:
        rh->serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        break;
    }

    /* Could not decrypt the UserIdentityToken */
    if(rh->serviceResult != UA_STATUSCODE_GOOD)
        UA_SECURITY_REJECT;

    /* Callback into the access control plugin.
     * This will attach a custom context pointer to the session. */
    rh->serviceResult = server->config.accessControl.
        activateSession(server, &server->config.accessControl, ed,
                        &channel->remoteCertificate, &session->sessionId,
                        &req->userIdentityToken, &session->context);
    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: The AccessControl plugin "
                             "denied the activation with the StatusCode %s",
                             UA_StatusCode_name(rh->serviceResult));
        UA_SECURITY_REJECT;
    }

    /* Attach the session to the currently used channel if the session isn't
     * attached to a channel or if the session is activated on a different
     * channel than it is attached to. */
    if(!session->channel || session->channel != channel) {
        /* Attach the new SecureChannel, the old channel will be detached if present */
        UA_Session_attachToSecureChannel(server, session, channel);
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "ActivateSession: Session attached to new channel");
    }

    /* Generate a new session nonce for the next time ActivateSession is called */
    rh->serviceResult = UA_Session_generateNonce(session);
    rh->serviceResult |= UA_ByteString_copy(&session->serverNonce,
                                            &resp->serverNonce);
    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        UA_Session_detachFromSecureChannel(server, session);
        UA_LOG_ERROR_SESSION(server->config.logging, session,
                             "ActivateSession: Could not generate the server nonce");
        UA_SESSION_REJECT;
    }

    /* Set the Locale */
    if(req->localeIdsSize > 0) {
        /* Part 4, §5.6.3.2: This parameter only needs to be specified during
         * the first call to ActivateSession during a single application
         * Session. If it is not specified the Server shall keep using the
         * current localeIds for the Session. */
        UA_String *tmpLocaleIds;
        rh->serviceResult |=
            UA_Array_copy(req->localeIds, req->localeIdsSize,
                          (void**)&tmpLocaleIds, &UA_TYPES[UA_TYPES_STRING]);
        if(rh->serviceResult != UA_STATUSCODE_GOOD) {
            UA_Session_detachFromSecureChannel(server, session);
            UA_LOG_ERROR_SESSION(server->config.logging, session,
                                 "ActivateSession: Could not store the "
                                 "Session LocaleIds");
            UA_SESSION_REJECT;
        }
        UA_Array_delete(session->localeIds, session->localeIdsSize,
                        &UA_TYPES[UA_TYPES_STRING]);
        session->localeIds = tmpLocaleIds;
        session->localeIdsSize = req->localeIdsSize;
    }

    /* Update the Session lifetime */
    UA_DateTime now = el->dateTime_now(el);
    nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_Session_updateLifetime(session, now, nowMonotonic);

    /* If ECC policy, create the new ephemeral key to be returned in the
     * ActivateSession response */
    const UA_SecurityPolicy *sessionSp = session->sessionSp;
    if(sessionSp && session->sessionSpContext &&
       UA_SecurityPolicy_isEcc(sessionSp) &&
       clientRequestedEphemeralKey(&req->requestHeader.additionalHeader)) {
        rh->serviceResult = addEphemeralKeyAdditionalHeader(server, session,
                                                            &rh->additionalHeader);
        if(rh->serviceResult != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_SESSION(server->config.logging, session,
                                 "ActivateSession: Could not prepare the "
                                 "ephemeral key (%s)",
                                 UA_StatusCode_name(rh->serviceResult));
            UA_SECURITY_REJECT;
        }
    }

    /* Activate the session */
    if(!session->activated) {
        session->activated = true;
        server->activeSessionCount++;
        server->serverDiagnosticsSummary.cumulatedSessionCount++;
    }

    /* Store the ClientUserId. tokenType can be NULL for the anonymous user. */
    UA_String_clear(&session->clientUserIdOfSession);
    const UA_DataType *tokenType = req->userIdentityToken.content.decoded.type;
    if(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
        const UA_UserNameIdentityToken *userToken = (UA_UserNameIdentityToken*)
            req->userIdentityToken.content.decoded.data;
        UA_String_copy(&userToken->userName, &session->clientUserIdOfSession);
    } else if(tokenType == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) {
        UA_X509IdentityToken* userCertToken = (UA_X509IdentityToken*)
            req->userIdentityToken.content.decoded.data;
        UA_CertificateUtils_getSubjectName(&session->clientUserIdOfSession,
                                           &userCertToken->certificateData);
    } else {
        /* TODO: Handle issued token */
    }

#ifdef UA_ENABLE_DIAGNOSTICS
    /* Add the ClientUserId to the diagnostics history. Ignoring errors in _appendCopy. */
    UA_SessionSecurityDiagnosticsDataType *ssd = &session->securityDiagnostics;
    UA_Array_appendCopy((void**)&ssd->clientUserIdHistory,
                        &ssd->clientUserIdHistorySize,
                        &ssd->clientUserIdOfSession,
                        &UA_TYPES[UA_TYPES_STRING]);

    /* Store the auth mechanism */
    UA_String_clear(&ssd->authenticationMechanism);
    switch(utp->tokenType) {
    case UA_USERTOKENTYPE_ANONYMOUS:
        ssd->authenticationMechanism = UA_STRING_ALLOC("Anonymous"); break;
    case UA_USERTOKENTYPE_USERNAME:
        ssd->authenticationMechanism = UA_STRING_ALLOC("UserName"); break;
    case UA_USERTOKENTYPE_CERTIFICATE:
        ssd->authenticationMechanism = UA_STRING_ALLOC("Certificate"); break;
    case UA_USERTOKENTYPE_ISSUEDTOKEN:
        ssd->authenticationMechanism = UA_STRING_ALLOC("IssuedToken"); break;
    default: break;
    }
#endif

    /* Notify the application */
    notifySession(server, session, UA_APPLICATIONNOTIFICATIONTYPE_SESSION_ACTIVATED);

    /* Log the user for which the Session was activated */
    UA_LOG_INFO_SESSION(server->config.logging, session,
                        "ActivateSession: Session activated with ClientUserId \"%S\"",
                        session->clientUserIdOfSession);
}

void
Service_CloseSession(UA_Server *server, UA_SecureChannel *channel,
                     const UA_CloseSessionRequest *request,
                     UA_CloseSessionResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_ResponseHeader *rh = &response->responseHeader;

    /* Part 4, 5.6.4: When the CloseSession Service is called before the Session
     * is successfully activated, the Server shall reject the request if the
     * SecureChannel is not the same as the one associated with the
     * CreateSession request.
     *
     * A non-activated Session is already bound to the SecureChannel that
     * created the Session. */
    UA_Session *session = NULL;
    const UA_NodeId *authToken = &request->requestHeader.authenticationToken;
    rh->serviceResult = getBoundSession(server, channel, authToken, &session);
    if(!session && rh->serviceResult == UA_STATUSCODE_GOOD)
        rh->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
    if(rh->serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "CloseSession: No Session activated to the SecureChannel");
        return;
    }

    UA_assert(session); /* Assured by the previous section */
    UA_LOG_INFO_SESSION(server->config.logging, session, "Closing the Session");

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* If Subscriptions are not deleted, detach them from the Session */
    if(!request->deleteSubscriptions) {
        UA_Subscription *sub, *sub_tmp;
        TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, sub_tmp) {
            UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                                     "Detaching the Subscription from the Session");
            UA_Session_detachSubscription(server, session, sub, true);
        }
    }
#endif

    /* Remove the sesison */
    UA_Session_remove(server, session, UA_SHUTDOWNREASON_CLOSE);
}

UA_Boolean
Service_Cancel(UA_Server *server, UA_Session *session,
               const UA_CancelRequest *request, UA_CancelResponse *response) {
    /* If multithreading is disabled, then there are no async services. If all
     * services are answered "right away", then there are no services that can
     * be cancelled. */
    response->cancelCount = UA_AsyncManager_cancel(server, session,
                                                   request->requestHandle);

    /* Publish requests for Subscriptions are stored separately */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_PublishResponseEntry *pre, *pre_tmp;
    UA_PublishResponseEntry *prev = NULL;
    SIMPLEQ_FOREACH_SAFE(pre, &session->responseQueue, listEntry, pre_tmp) {
        /* Skip entry and set as the previous entry that is kept in the list */
        if(pre->response.responseHeader.requestHandle != request->requestHandle) {
            prev = pre;
            continue;
        }

        /* Dequeue */
        if(prev)
            SIMPLEQ_REMOVE_AFTER(&session->responseQueue, prev, listEntry);
        else
            SIMPLEQ_REMOVE_HEAD(&session->responseQueue, listEntry);
        session->responseQueueSize--;

        /* Send response and clean up */
        response->responseHeader.serviceResult = UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT;
        sendResponse(server, session->channel, pre->requestId, (UA_Response *)response,
                     &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
        UA_PublishResponse_clear(&pre->response);
        UA_free(pre);

        /* Increase the CancelCount */
        response->cancelCount++;
    }
#endif

    return true;
}

/**** amalgamated original file "/src/server/ua_services_attribute.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015 (c) Christian Fimmers
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2015 (c) wuyangtang
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Thomas Bender
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart  (for VDW and umati)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_HISTORIZING
#endif

static const UA_NodeAttributesMask attr2mask[28] = {
    UA_NODEATTRIBUTESMASK_NODEID,
    UA_NODEATTRIBUTESMASK_NODECLASS,
    UA_NODEATTRIBUTESMASK_BROWSENAME,
    UA_NODEATTRIBUTESMASK_DISPLAYNAME,
    UA_NODEATTRIBUTESMASK_DESCRIPTION,
    UA_NODEATTRIBUTESMASK_WRITEMASK,
    UA_NODEATTRIBUTESMASK_USERWRITEMASK,
    UA_NODEATTRIBUTESMASK_ISABSTRACT,
    UA_NODEATTRIBUTESMASK_SYMMETRIC,
    UA_NODEATTRIBUTESMASK_INVERSENAME,
    UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS,
    UA_NODEATTRIBUTESMASK_EVENTNOTIFIER,
    UA_NODEATTRIBUTESMASK_VALUE,
    UA_NODEATTRIBUTESMASK_DATATYPE,
    UA_NODEATTRIBUTESMASK_VALUERANK,
    UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS,
    UA_NODEATTRIBUTESMASK_ACCESSLEVEL,
    UA_NODEATTRIBUTESMASK_USERACCESSLEVEL,
    UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL,
    UA_NODEATTRIBUTESMASK_HISTORIZING,
    UA_NODEATTRIBUTESMASK_EXECUTABLE,
    UA_NODEATTRIBUTESMASK_USEREXECUTABLE,
    UA_NODEATTRIBUTESMASK_DATATYPEDEFINITION,
    UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS,
    UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS,
    UA_NODEATTRIBUTESMASK_ACCESSRESTRICTIONS,
    UA_NODEATTRIBUTESMASK_ACCESSLEVEL
};

static UA_UInt32
attributeId2AttributeMask(UA_AttributeId id) {
    if(UA_UNLIKELY(id > UA_ATTRIBUTEID_ACCESSLEVELEX))
        return UA_NODEATTRIBUTESMASK_NONE;
    return attr2mask[id];
}

/******************/
/* Access Control */
/******************/

/* Session for read operations can be NULL. For example for a MonitoredItem
 * where the underlying Subscription was detached during CloseSession. */

static UA_UInt32
getUserWriteMask(UA_Server *server, const UA_Session *session,
                 const UA_NodeHead *head) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    if(session == &server->adminSession)
        return 0xFFFFFFFF; /* the local admin user has all rights */
    return head->writeMask & server->config.accessControl.
        getUserRightsMask(server, &server->config.accessControl,
                          session ? &session->sessionId : NULL,
                          session ? session->context : NULL,
                          &head->nodeId, head->context);
}

static UA_Byte
getAccessLevel(UA_Server *server, const UA_Session *session,
               const UA_VariableNode *node) {
    if(session == &server->adminSession)
        return 0xFF; /* the local admin user has all rights */
    return node->accessLevel;
}

static UA_Byte
getUserAccessLevel(UA_Server *server, const UA_Session *session,
                   const UA_VariableNode *node) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    if(session == &server->adminSession)
        return 0xFF; /* the local admin user has all rights */
    return node->accessLevel & server->config.accessControl.
        getUserAccessLevel(server, &server->config.accessControl,
                           session ? &session->sessionId : NULL,
                           session ? session->context : NULL,
                           &node->head.nodeId, node->head.context);
}

static UA_Boolean
getUserExecutable(UA_Server *server, const UA_Session *session,
                  const UA_MethodNode *node) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    if(session == &server->adminSession)
        return true; /* the local admin user has all rights */
    return node->executable & server->config.accessControl.
        getUserExecutable(server, &server->config.accessControl,
                          session ? &session->sessionId : NULL,
                          session ? session->context : NULL,
                          &node->head.nodeId, node->head.context);
}

/****************/
/* Read Service */
/****************/

static UA_StatusCode
readIsAbstractAttribute(const UA_Node *node, UA_Variant *v) {
    const UA_Boolean *isAbstract;
    switch(node->head.nodeClass) {
    case UA_NODECLASS_REFERENCETYPE:
        isAbstract = &node->referenceTypeNode.isAbstract;
        break;
    case UA_NODECLASS_OBJECTTYPE:
        isAbstract = &node->objectTypeNode.isAbstract;
        break;
    case UA_NODECLASS_VARIABLETYPE:
        isAbstract = &node->variableTypeNode.isAbstract;
        break;
    case UA_NODECLASS_DATATYPE:
        isAbstract = &node->dataTypeNode.isAbstract;
        break;
    default:
        return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
    }

    return UA_Variant_setScalarCopy(v, isAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

static UA_StatusCode
readInternalValueAttribute(UA_Server *server, UA_Session *session,
                           const UA_VariableNode *vn, UA_DataValue *v,
                           UA_NumericRange *rangeptr) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Update the value by the user callback */
    if(vn->valueSource.internal.notifications.onRead) {
        vn->valueSource.internal.notifications.
            onRead(server, session ? &session->sessionId : NULL,
                   session ? session->context : NULL, &vn->head.nodeId,
                   vn->head.context, rangeptr, &vn->valueSource.internal.value);
        vn = (const UA_VariableNode*)
            UA_NODESTORE_GET_SELECTIVE(server, &vn->head.nodeId,
                                       UA_NODEATTRIBUTESMASK_VALUE,
                                       UA_REFERENCETYPESET_NONE,
                                       UA_BROWSEDIRECTION_INVALID);
        if(!vn)
            return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    /* Set the result */
    UA_StatusCode retval = (!rangeptr) ?
        UA_DataValue_copy(&vn->valueSource.internal.value, v) :
        UA_DataValue_copyRange(&vn->valueSource.internal.value, v, *rangeptr);

    /* Clean up */
    if(vn->valueSource.internal.notifications.onRead)
        UA_NODESTORE_RELEASE(server, (const UA_Node *)vn);
    return retval;
}

static UA_StatusCode
readExternalValueAttribute(UA_Server *server, UA_Session *session,
                           const UA_VariableNode *vn, UA_DataValue *v,
                           UA_NumericRange *rangeptr) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Update the value by the user callback */
    if(vn->valueSource.internal.notifications.onRead)
        vn->valueSource.internal.notifications.
            onRead(server, session ? &session->sessionId : NULL,
                   session ? session->context : NULL, &vn->head.nodeId,
                   vn->head.context, rangeptr, *vn->valueSource.external.value);

    /* Reload the value pointer */
    const UA_DataValue *val = (const UA_DataValue*)
        UA_atomic_load((void**)vn->valueSource.external.value);

    /* Set the result */
    return (!rangeptr) ? UA_DataValue_copy(val, v) : UA_DataValue_copyRange(val, v, *rangeptr);
}

static UA_StatusCode
readCallbackValueAttribute(UA_Server *server, UA_Session *session,
                           const UA_VariableNode *vn, UA_DataValue *v,
                           UA_TimestampsToReturn timestamps,
                           UA_NumericRange *rangeptr) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(!vn->valueSource.callback.read)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
                                  timestamps == UA_TIMESTAMPSTORETURN_BOTH);
    UA_StatusCode retval = vn->valueSource.callback.
        read(server,
             session ? &session->sessionId : NULL,
             session ? session->context : NULL,
             &vn->head.nodeId, vn->head.context,
             sourceTimeStamp, rangeptr, v);
    if(retval == UA_STATUSCODE_GOOD && v->hasValue &&
       v->value.storageType == UA_VARIANT_DATA_NODELETE) {
        UA_DataValue v2;
        retval = UA_DataValue_copy(v, &v2);
        *v = v2;
    }
    return retval;
}

/* OPC UA Part 6: Non-nullable built-in types are Boolean and the 
 * numeric types (SByte..Double), StatusCode and Enumerations.
 * All remaining built-in types are nullable. */
static bool
isNullableDataType(UA_Server *server, const UA_NodeId *dataType) {
    const UA_DataType *type = UA_Server_findDataType(server, dataType);
    if(!type)
        return true; /* Unknown type */
    if(UA_DataType_isNumeric(type))
        return false;
    switch(type->typeKind) {
        case UA_DATATYPEKIND_BOOLEAN:
        case UA_DATATYPEKIND_STATUSCODE:
        case UA_DATATYPEKIND_ENUM:
            return false;
        default:
            return true;
    }
}

static UA_StatusCode
readValueAttributeComplete(UA_Server *server, UA_Session *session,
                           const UA_VariableNode *vn, UA_TimestampsToReturn timestamps,
                           const UA_String *indexRange, UA_DataValue *v) {
    UA_EventLoop *el = server->config.eventLoop;

    /* Parse the index range */
    UA_NumericRange range;
    UA_NumericRange *rangeptr = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(indexRange && indexRange->length > 0) {
        retval = UA_NumericRange_parse(&range, *indexRange);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        rangeptr = &range;
    }

    /* Read from the value souce */
    switch(vn->valueSourceType) {
    case UA_VALUESOURCETYPE_INTERNAL:
        retval = readInternalValueAttribute(server, session, vn, v, rangeptr);
        break;
    case UA_VALUESOURCETYPE_EXTERNAL:
        retval = readExternalValueAttribute(server, session, vn, v, rangeptr);
        break;
    case UA_VALUESOURCETYPE_CALLBACK:
        retval = readCallbackValueAttribute(server, session, vn, v, timestamps, rangeptr);
        break;
    default:
        retval = UA_STATUSCODE_BADINTERNALERROR;
        break;
    }

    /* If not defined return a source timestamp of "now".
     * Static nodes always have the current time as source-time. */
    if(!v->hasSourceTimestamp) {
        v->sourceTimestamp = el->dateTime_now(el);
        v->hasSourceTimestamp = true;
    }

    /* Clean up */
    if(rangeptr)
        UA_free(range.dimensions);
    return retval;
}

UA_StatusCode
readValueAttribute(UA_Server *server, UA_Session *session,
                   const UA_VariableNode *vn, UA_DataValue *v) {
    return readValueAttributeComplete(server, session, vn,
                                      UA_TIMESTAMPSTORETURN_NEITHER, NULL, v);
}

static const UA_String binEncoding = {sizeof("Default Binary")-1, (UA_Byte*)"Default Binary"};
static const UA_String xmlEncoding = {sizeof("Default XML")-1, (UA_Byte*)"Default XML"};
static const UA_String jsonEncoding = {sizeof("Default JSON")-1, (UA_Byte*)"Default JSON"};

#define CHECK_NODECLASS(CLASS)                                  \
    if(!(node->head.nodeClass & (CLASS))) {                     \
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;           \
        break;                                                  \
    }

static void
addMissingTimestamps(UA_Server *server, UA_DataValue *v,
              UA_TimestampsToReturn timestampsToReturn,
              const UA_ReadValueId *id) {
    /* Always use the current time as the server-timestamp */
    if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER ||
       timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH) {
        UA_EventLoop *el = server->config.eventLoop;
        v->serverTimestamp = el->dateTime_now(el);
        v->hasServerTimestamp = true;
        v->hasServerPicoseconds = false;
    } else {
        v->hasServerTimestamp = false;
        v->hasServerPicoseconds = false;
    }

    /* Remove source timestamps when not required */
    if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER ||
       timestampsToReturn == UA_TIMESTAMPSTORETURN_NEITHER) {
        v->hasSourceTimestamp = false;
        v->hasSourcePicoseconds = false;
    } else if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SOURCE ||
              timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH) {
        /* Optional behavior and not required by the specification: Always
         * set a SourceTimestamp for the value attribute, even if the value
         * source didn't return one. */
        if(!v->hasSourceTimestamp && id->attributeId == UA_ATTRIBUTEID_VALUE) {
            UA_EventLoop *el = server->config.eventLoop;
            v->sourceTimestamp = el->dateTime_now(el);
            v->hasSourceTimestamp = true;
            v->hasSourcePicoseconds = false;
        }
    }
}

/* Returns whether the operation is done or an async operation has been
 * triggered. */
static UA_Boolean
ReadWithNodeMaybeAsync(const UA_Node *node, UA_Server *server, UA_Session *session,
                       UA_TimestampsToReturn timestampsToReturn,
                       const UA_ReadValueId *id, UA_DataValue *v) {
    UA_LOG_TRACE_SESSION(server->config.logging, session,
                         "Read attribute %"PRIi32 " of Node %N",
                         id->attributeId, node->head.nodeId);

    /* Only Binary Encoding is supported */
    if(id->dataEncoding.name.length > 0 &&
       !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
        if(UA_String_equal(&xmlEncoding, &id->dataEncoding.name) ||
           UA_String_equal(&jsonEncoding, &id->dataEncoding.name))
           v->status = UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED;
        else
           v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
        v->hasStatus = true;
        addMissingTimestamps(server, v, timestampsToReturn, id);
        return true;
    }

    /* Index range for an attribute other than value */
    if(id->indexRange.length > 0 && id->attributeId != UA_ATTRIBUTEID_VALUE) {
        v->hasStatus = true;
        v->status = UA_STATUSCODE_BADINDEXRANGENODATA;
        addMissingTimestamps(server, v, timestampsToReturn, id);
        return true;
    }

    /* Read the attribute */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(id->attributeId) {
    case UA_ATTRIBUTEID_NODEID:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.nodeId,
                                          &UA_TYPES[UA_TYPES_NODEID]);
        break;
    case UA_ATTRIBUTEID_NODECLASS:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.nodeClass,
                                          &UA_TYPES[UA_TYPES_NODECLASS]);
        break;
    case UA_ATTRIBUTEID_BROWSENAME:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.browseName,
                                          &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
        break;
    case UA_ATTRIBUTEID_DISPLAYNAME: {
        UA_LocalizedText lt = UA_Session_getNodeDisplayName(session, &node->head);
        retval = UA_Variant_setScalarCopy(&v->value, &lt,
                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        break;
    }
    case UA_ATTRIBUTEID_DESCRIPTION: {
        UA_LocalizedText lt = UA_Session_getNodeDescription(session, &node->head);
        retval = UA_Variant_setScalarCopy(&v->value, &lt,
                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        break;
    }
    case UA_ATTRIBUTEID_WRITEMASK:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.writeMask,
                                          &UA_TYPES[UA_TYPES_UINT32]);
        break;
    case UA_ATTRIBUTEID_USERWRITEMASK: {
        UA_UInt32 userWriteMask = getUserWriteMask(server, session, &node->head);
        retval = UA_Variant_setScalarCopy(&v->value, &userWriteMask,
                                          &UA_TYPES[UA_TYPES_UINT32]);
        break;
    }
    case UA_ATTRIBUTEID_ISABSTRACT:
        retval = readIsAbstractAttribute(node, &v->value);
        break;
    case UA_ATTRIBUTEID_SYMMETRIC:
        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->referenceTypeNode.symmetric,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_INVERSENAME:
        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
        if(node->referenceTypeNode.symmetric) {
            /* Symmetric reference types don't have an inverse name */
            retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
            break;
        }
        retval = UA_Variant_setScalarCopy(&v->value, &node->referenceTypeNode.inverseName,
                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        break;
    case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
        CHECK_NODECLASS(UA_NODECLASS_VIEW);
        retval = UA_Variant_setScalarCopy(&v->value, &node->viewNode.containsNoLoops,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
        if(node->head.nodeClass == UA_NODECLASS_VIEW) {
            retval = UA_Variant_setScalarCopy(&v->value, &node->viewNode.eventNotifier,
                                              &UA_TYPES[UA_TYPES_BYTE]);
        } else {
            retval = UA_Variant_setScalarCopy(&v->value, &node->objectNode.eventNotifier,
                                              &UA_TYPES[UA_TYPES_BYTE]);
        }
        break;
    case UA_ATTRIBUTEID_VALUE: {
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        /* VariableTypes don't have the AccessLevel concept. Always allow
         * reading the value. */
        if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
            /* The access to a value variable is granted via the UserAccessLevel
             * attribute (masked with the AccessLevel attribute) */
            UA_Byte accessLevel = getUserAccessLevel(server, session, &node->variableNode);
            if(!(accessLevel & (UA_ACCESSLEVELMASK_READ))) {
                retval = UA_STATUSCODE_BADUSERACCESSDENIED;
                break;
            }
        }
        retval = readValueAttributeComplete(server, session, &node->variableNode,
                                            timestampsToReturn, &id->indexRange, v);
        break;
    }
    case UA_ATTRIBUTEID_DATATYPE:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableTypeNode.dataType,
                                          &UA_TYPES[UA_TYPES_NODEID]);
        break;
    case UA_ATTRIBUTEID_VALUERANK:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableTypeNode.valueRank,
                                          &UA_TYPES[UA_TYPES_INT32]);
        break;
    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        retval = UA_Variant_setArrayCopy(&v->value, node->variableTypeNode.arrayDimensions,
                                         node->variableTypeNode.arrayDimensionsSize,
                                         &UA_TYPES[UA_TYPES_UINT32]);
        break;
    case UA_ATTRIBUTEID_ACCESSLEVEL:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableNode.accessLevel,
                                          &UA_TYPES[UA_TYPES_BYTE]);
        break;
    case UA_ATTRIBUTEID_ACCESSLEVELEX: {
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        /* The normal AccessLevelEx contains the lowest 8 bits from the normal AccessLevel.
         * In our case, all other bits are zero. */
        const UA_Byte accessLevel = *((const UA_Byte*)(&node->variableNode.accessLevel));
        UA_UInt32 accessLevelEx = accessLevel & 0xFF;
        retval = UA_Variant_setScalarCopy(&v->value, &accessLevelEx,
                                          &UA_TYPES[UA_TYPES_UINT32]);

        break;
    }
    case UA_ATTRIBUTEID_USERACCESSLEVEL: {
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        UA_Byte userAccessLevel = getUserAccessLevel(server, session, &node->variableNode);
        retval = UA_Variant_setScalarCopy(&v->value, &userAccessLevel,
                                          &UA_TYPES[UA_TYPES_BYTE]);
        break;
    }
    case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        retval = UA_Variant_setScalarCopy(&v->value,
                                          &node->variableNode.minimumSamplingInterval,
                                          &UA_TYPES[UA_TYPES_DOUBLE]);
        break;
    case UA_ATTRIBUTEID_HISTORIZING:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableNode.historizing,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_EXECUTABLE:
        CHECK_NODECLASS(UA_NODECLASS_METHOD);
        retval = UA_Variant_setScalarCopy(&v->value, &node->methodNode.executable,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_USEREXECUTABLE: {
        CHECK_NODECLASS(UA_NODECLASS_METHOD);
        UA_Boolean userExecutable =
            getUserExecutable(server, session, &node->methodNode);
        retval = UA_Variant_setScalarCopy(&v->value, &userExecutable,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    }
    case UA_ATTRIBUTEID_DATATYPEDEFINITION: {
        CHECK_NODECLASS(UA_NODECLASS_DATATYPE);
#ifdef UA_ENABLE_TYPEDESCRIPTION
        /* Find the DataType */
        const UA_DataType *type =
            UA_findDataTypeWithCustom(&node->head.nodeId, serverCustomTypes(server));
        if(!type) {
            retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
            break;
        }

        UA_ExtensionObject typeDescr;
        retval = UA_DataType_toDescription(type, &typeDescr);
        if(UA_STATUSCODE_GOOD != retval)
            break;

        if(typeDescr.content.decoded.type == &UA_TYPES[UA_TYPES_STRUCTUREDESCRIPTION]) {
            UA_StructureDescription *sd = (UA_StructureDescription*)
                typeDescr.content.decoded.data;
            UA_NodeId_clear(&sd->dataTypeId);
            UA_QualifiedName_clear(&sd->name);
            memmove(sd, &sd->structureDefinition, sizeof(UA_StructureDefinition));
            UA_Variant_setScalar(&v->value, sd, &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]);
        } else if(typeDescr.content.decoded.type == &UA_TYPES[UA_TYPES_ENUMDESCRIPTION] && type->membersSize > 0) {
            /* UaExpert doesn't fall back to the EnumStrings property if the DataTypeDefinition attribute
               can be read but has no fields. This breaks its method call dialog for enum parameters. */

            UA_EnumDescription *ed = (UA_EnumDescription*)
                typeDescr.content.decoded.data;
            UA_NodeId_clear(&ed->dataTypeId);
            UA_QualifiedName_clear(&ed->name);
            memmove(ed, &ed->enumDefinition, sizeof(UA_EnumDefinition));
            UA_Variant_setScalar(&v->value, ed, &UA_TYPES[UA_TYPES_ENUMDEFINITION]);
        } else {
            retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
        }
#else
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
#endif
        break;
    }
    case UA_ATTRIBUTEID_ROLEPERMISSIONS:
    case UA_ATTRIBUTEID_USERROLEPERMISSIONS:
    case UA_ATTRIBUTEID_ACCESSRESTRICTIONS:
        /* TODO: Add support for the attributes from the 1.04 spec */
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
        break;

    default:
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
    }

    /* Reading has failed? */
    if(retval == UA_STATUSCODE_GOOD) {
        v->hasValue = true;
    } else if(retval != UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY) {
        /* Signal that reading has failed. Otherwise keep the status returned
         * from the value source. Ignore the async processing sentinel
         * status. */
        v->hasStatus = true;
        v->status = retval;
    }

    /* OPC UA Part 4:  StatusCode Good is only permitted for nullable
     * DataTypes. Non-nullable must have a Bad StatusCode
     * when no value is available. Only apply this check if no other
     * error has occurred. */
    if(retval == UA_STATUSCODE_GOOD &&
       v->hasValue && UA_Variant_isEmpty(&v->value) &&
       (node->head.nodeClass == UA_NODECLASS_VARIABLE ||
        node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) &&
       !isNullableDataType(server, &node->variableNode.dataType)) {
        v->hasValue = false;
        v->hasStatus = true;
        v->status = UA_STATUSCODE_BADWAITINGFORINITIALDATA;
    }

    addMissingTimestamps(server, v, timestampsToReturn, id);

    /* Are we done or is this an async read? */
    return (retval != UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY);
}

UA_Boolean
Operation_Read(UA_Server *server, UA_Session *session,
               UA_TimestampsToReturn ttr,
               const UA_ReadValueId *rvi, UA_DataValue *dv) {
    /* Get the node (with only the selected attribute if the NodeStore supports that) */
    UA_UInt32 attrMask = attributeId2AttributeMask((UA_AttributeId)rvi->attributeId);
    const UA_Node *node =
        UA_NODESTORE_GET_SELECTIVE(server, &rvi->nodeId, attrMask,
                                   UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID);
    if(!node) {
        dv->hasStatus = true;
        dv->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return true;
    }

    /* Perform the read operation */
    UA_Boolean done = ReadWithNodeMaybeAsync(node, server, session, ttr, rvi, dv);
    UA_NODESTORE_RELEASE(server, node);
    return done;
}

UA_DataValue
readWithSession(UA_Server *server, UA_Session *session,
                const UA_ReadValueId *item,
                UA_TimestampsToReturn ttr) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_DataValue dv;
    UA_DataValue_init(&dv);

    /* No Session defined. This can happen for example when a Subscription is
     * detached from its Session. */
    if(!session) {
        dv.hasStatus = true;
        dv.status = UA_STATUSCODE_BADUSERACCESSDENIED;
        return dv;
    }

    UA_Boolean done = Operation_Read(server, session, ttr, item, &dv);
    if(!done) {
        if(server->config.asyncOperationCancelCallback)
            server->config.asyncOperationCancelCallback(server, &dv);
        dv.hasStatus = true;
        dv.status = UA_STATUSCODE_BADWAITINGFORRESPONSE;
    }
    return dv;
}

UA_StatusCode
readWithReadValue(UA_Server *server, const UA_NodeId *nodeId,
                  const UA_AttributeId attributeId, void *v) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Call the read service */
    UA_ReadValueId item;
    UA_ReadValueId_init(&item);
    item.nodeId = *nodeId;
    item.attributeId = attributeId;
    UA_DataValue dv = readWithSession(server, &server->adminSession,
                                      &item, UA_TIMESTAMPSTORETURN_NEITHER);

    /* Check the return value */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    /* The status may be uncertain */
    if(dv.hasStatus && dv.status >= UA_STATUSCODE_BAD)
        retval = dv.status;
    else if(!dv.hasValue)
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DataValue_clear(&dv);
        return retval;
    }

    if(attributeId == UA_ATTRIBUTEID_VALUE ||
       attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS) {
        /* Return the entire variant */
        memcpy(v, &dv.value, sizeof(UA_Variant));
    } else {
        /* Return the variant content only */
        memcpy(v, dv.value.data, dv.value.type->memSize);
        UA_free(dv.value.data);
    }
    return retval;
}

/* Exposes the Read service to local users */
UA_DataValue
UA_Server_read(UA_Server *server, const UA_ReadValueId *item,
               UA_TimestampsToReturn timestamps) {
    lockServer(server);
    UA_DataValue dv = readWithSession(server, &server->adminSession, item, timestamps);
    unlockServer(server);
    return dv;
}

/* Used in inline functions exposing the Read service with more syntactic sugar
 * for individual attributes */
static UA_StatusCode
__Server_read(UA_Server *server, const UA_NodeId *nodeId,
                 const UA_AttributeId attributeId, void *v) {
   lockServer(server);
   UA_StatusCode retval = readWithReadValue(server, nodeId, attributeId, v);
   unlockServer(server);
   return retval;
}

UA_StatusCode
UA_Server_readNodeId(UA_Server *server, const UA_NodeId nodeId, UA_NodeId *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_NODEID, out);
}

UA_StatusCode
UA_Server_readNodeClass(UA_Server *server, const UA_NodeId nodeId, UA_NodeClass *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_NODECLASS, out);
}

UA_StatusCode
UA_Server_readBrowseName(UA_Server *server, const UA_NodeId nodeId, UA_QualifiedName *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, out);
}

UA_StatusCode
UA_Server_readDisplayName(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, out);
}

UA_StatusCode
UA_Server_readDescription(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, out);
}

UA_StatusCode
UA_Server_readWriteMask(UA_Server *server, const UA_NodeId nodeId, UA_UInt32 *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, out);
}

UA_StatusCode
UA_Server_readIsAbstract(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, out);
}

UA_StatusCode
UA_Server_readSymmetric(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, out);
}

UA_StatusCode
UA_Server_readInverseName(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, out);
}

UA_StatusCode
UA_Server_readContainsNoLoops(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, out);
}

UA_StatusCode
UA_Server_readEventNotifier(UA_Server *server, const UA_NodeId nodeId, UA_Byte *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, out);
}

UA_StatusCode
UA_Server_readValue(UA_Server *server, const UA_NodeId nodeId, UA_Variant *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUE, out);
}

UA_StatusCode
UA_Server_readDataType(UA_Server *server, const UA_NodeId nodeId, UA_NodeId *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_DATATYPE, out);
}

UA_StatusCode
UA_Server_readValueRank(UA_Server *server, const UA_NodeId nodeId, UA_Int32 *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUERANK, out);
}

UA_StatusCode
UA_Server_readArrayDimensions(UA_Server *server, const UA_NodeId nodeId, UA_Variant *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, out);
}

UA_StatusCode
UA_Server_readAccessLevel(UA_Server *server, const UA_NodeId nodeId, UA_Byte *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, out);
}

UA_StatusCode
UA_Server_readAccessLevelEx(UA_Server *server, const UA_NodeId nodeId, UA_UInt32 *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX, out);
}

UA_StatusCode
UA_Server_readMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, UA_Double *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, out);
}

UA_StatusCode
UA_Server_readHistorizing(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING, out);
}

UA_StatusCode
UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *out) {
    return __Server_read(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, out);
}

UA_StatusCode
readObjectProperty(UA_Server *server, const UA_NodeId objectId,
                   const UA_QualifiedName propertyName,
                   UA_Variant *value) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Create a BrowsePath to get the target NodeId */
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = UA_NS0ID(HASPROPERTY);
    rpe.isInverse = false;
    rpe.includeSubtypes = false;
    rpe.targetName = propertyName;

    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = objectId;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;

    UA_StatusCode retval;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_BrowsePathResult_clear(&bpr);
        return retval;
    }

    /* Use the first result from the BrowsePath */
    retval = readWithReadValue(server, &bpr.targets[0].targetId.nodeId,
                               UA_ATTRIBUTEID_VALUE, value);

    UA_BrowsePathResult_clear(&bpr);
    return retval;
}


UA_StatusCode
UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId,
                             const UA_QualifiedName propertyName,
                             UA_Variant *value) {
    lockServer(server);
    UA_StatusCode retval = readObjectProperty(server, objectId, propertyName, value);
    unlockServer(server);
    return retval;
}

/*****************/
/* Type Checking */
/*****************/

UA_Boolean
compatibleValueDataType(UA_Server *server, const UA_DataType *dataType,
                        const UA_NodeId *constraintDataType) {
    if(compatibleDataTypes(server, &dataType->typeId, constraintDataType))
        return true;

    /* For actual values, the constraint DataType may be a subtype of the
     * DataType of the value -- subtyping in the wrong direction. E.g. UtcTime
     * is a subtype of DateTime. But we allow the value to be encoded as a
     * DateTime value when transferred over the wire.
     *
     * Note that all structures are subtypes of ExtensionObject (== Structure in
     * the Node hierarchy). But we usually do not encounter ExtensionObjects
     * here. Because the values are typically unwrapped from the ExtensionObject
     * during the decoding. */
    return isNodeInTree_singleRef(server, constraintDataType, &dataType->typeId,
                                  UA_REFERENCETYPEINDEX_HASSUBTYPE);
}

UA_Boolean
compatibleDataTypes(UA_Server *server, const UA_NodeId *dataType,
                    const UA_NodeId *constraintDataType) {
    /* Do not allow empty datatypes */
    if(UA_NodeId_isNull(dataType))
       return false;

    /* No constraint or Variant / BaseDataType which allows any content */
    if(UA_NodeId_isNull(constraintDataType) ||
       UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId))
        return true;

    /* Same datatypes */
    if(UA_NodeId_equal(dataType, constraintDataType))
        return true;

    /* Is the DataType a subtype of the constraint type? */
    if(isNodeInTree_singleRef(server, dataType, constraintDataType,
                              UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return true;

    return false;
}

/* Test whether a ValueRank and the given arraydimensions are compatible.
 *
 * 5.6.2 Variable NodeClass: If the maximum is unknown the value shall be 0. The
 * number of elements shall be equal to the value of the ValueRank Attribute.
 * This Attribute shall be null if ValueRank <= 0. */
UA_Boolean
compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session,
                                   UA_Int32 valueRank, size_t arrayDimensionsSize) {
    /* ValueRank invalid */
    if(valueRank < UA_VALUERANK_SCALAR_OR_ONE_DIMENSION) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "The ValueRank is invalid (< -3)");
        return false;
    }

    /* case -3, UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: the value can be a scalar
     *   or a one dimensional array
     * case -2, UA_VALUERANK_ANY: the value can be a scalar or an array with any
     *   number of dimensions
     * case -1, UA_VALUERANK_SCALAR: the value is a scalar
     * case 0, UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: the value is an array with
     *   one or more dimensions */
    if(valueRank <= UA_VALUERANK_ONE_OR_MORE_DIMENSIONS) {
        if(arrayDimensionsSize > 0) {
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "No ArrayDimensions can be defined for a ValueRank <= 0");
            return false;
        }
        return true;
    }

    /* case >= 1, UA_VALUERANK_ONE_DIMENSION: the value is an array with the
       specified number of dimensions */
    if(arrayDimensionsSize != (size_t)valueRank) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "The number of ArrayDimensions is not equal to "
                            "the (positive) ValueRank");
        return false;
    }
    return true;
}

UA_Boolean
compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank) {
    /* Check if the valuerank of the variabletype allows the change. */
    switch(constraintValueRank) {
    case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* the value can be a scalar or a
                                                  one dimensional array */
        if(valueRank != UA_VALUERANK_SCALAR && valueRank != UA_VALUERANK_ONE_DIMENSION)
            return false;
        break;
    case UA_VALUERANK_ANY: /* the value can be a scalar or an array with any
                              number of dimensions */
        break;
    case UA_VALUERANK_SCALAR: /* the value is a scalar */
        if(valueRank != UA_VALUERANK_SCALAR)
            return false;
        break;
    case UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: /* the value is an array with one
                                                 or more dimensions */
        if(valueRank < (UA_Int32) UA_VALUERANK_ONE_OR_MORE_DIMENSIONS)
            return false;
        break;
    default: /* >= 1: the value is an array with the specified number of
                 dimensions */
        if(valueRank != constraintValueRank)
            return false;
        break;
    }
    return true;
}

/* Check if the ValueRank allows for the value dimension. This is more
 * permissive than checking for the ArrayDimensions attribute. Because the value
 * can have dimensions if the ValueRank < 0 */
static UA_Boolean
compatibleValueRankValue(UA_Int32 valueRank, const UA_Variant *value) {
    /* Invalid ValueRank */
    if(valueRank < UA_VALUERANK_SCALAR_OR_ONE_DIMENSION)
        return false;

    /* Empty arrays (-1) always match */
    if(!value->data)
        return true;

    size_t arrayDims = value->arrayDimensionsSize;
    if(arrayDims == 0 && !UA_Variant_isScalar(value))
        arrayDims = 1; /* array but no arraydimensions -> implicit array dimension 1 */

    /* We cannot simply use compatibleValueRankArrayDimensions since we can have
     * defined ArrayDimensions for the value if the ValueRank is -2 */
    switch(valueRank) {
    case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* The value can be a scalar or a
                                                  one dimensional array */
        return (arrayDims <= 1);
    case UA_VALUERANK_ANY: /* The value can be a scalar or an array with any
                              number of dimensions */
        return true;
    case UA_VALUERANK_SCALAR: /* The value is a scalar */
        return (arrayDims == 0);
    case UA_VALUERANK_ONE_OR_MORE_DIMENSIONS:
        return (arrayDims >= 1);
    default:
        break;
    }

    UA_assert(valueRank >= UA_VALUERANK_ONE_OR_MORE_DIMENSIONS);

    /* case 0:  the value is an array with one or more dimensions */
    return (arrayDims == (UA_UInt32)valueRank);
}

UA_Boolean
compatibleArrayDimensions(size_t constraintArrayDimensionsSize,
                          const UA_UInt32 *constraintArrayDimensions,
                          size_t testArrayDimensionsSize,
                          const UA_UInt32 *testArrayDimensions) {
    /* No array dimensions defined -> everything is permitted if the value rank fits */
    if(constraintArrayDimensionsSize == 0)
        return true;

    /* Dimension count must match */
    if(testArrayDimensionsSize != constraintArrayDimensionsSize)
        return false;

    /* Dimension lengths must not be larger than the constraint. Zero in the
     * constraint indicates a wildcard. */
    for(size_t i = 0; i < constraintArrayDimensionsSize; ++i) {
        if(constraintArrayDimensions[i] < testArrayDimensions[i] &&
           constraintArrayDimensions[i] != 0)
            return false;
    }
    return true;
}

UA_Boolean
compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimensionsSize,
                               const UA_UInt32 *targetArrayDimensions) {
    size_t valueArrayDimensionsSize = value->arrayDimensionsSize;
    UA_UInt32 const *valueArrayDimensions = value->arrayDimensions;
    UA_UInt32 tempArrayDimensions;
    if(!valueArrayDimensions && !UA_Variant_isScalar(value)) {
        /* An empty array implicitly has array dimensions [0,0,...] with the
         * correct number of dimensions. So it always matches. */
        if(value->arrayLength == 0)
            return true;

        /* Arrays with content and without array dimensions have one implicit dimension */
        valueArrayDimensionsSize = 1;
        tempArrayDimensions = (UA_UInt32)value->arrayLength;
        valueArrayDimensions = &tempArrayDimensions;
    }
    UA_assert(valueArrayDimensionsSize == 0 || valueArrayDimensions != NULL);
    return compatibleArrayDimensions(targetArrayDimensionsSize, targetArrayDimensions,
                                     valueArrayDimensionsSize, valueArrayDimensions);
}

static const char *reason_EmptyType = "Empty value only allowed for BaseDataType";
static const char *reason_ValueDataType = "DataType of the value is incompatible";
static const char *reason_ValueArrayDimensions = "ArrayDimensions of the value are incompatible";
static const char *reason_ValueValueRank = "ValueRank of the value is incompatible";

UA_Boolean
compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId,
                UA_Int32 targetValueRank, size_t targetArrayDimensionsSize,
                const UA_UInt32 *targetArrayDimensions, const UA_Variant *value,
                const UA_NumericRange *range, const char **reason) {
    /* Empty value */
    if(UA_Variant_isEmpty(value)) {
        /* Empty value is allowed for BaseDataType */
        if(UA_NodeId_equal(targetDataTypeId, &UA_TYPES[UA_TYPES_VARIANT].typeId) ||
           UA_NodeId_equal(targetDataTypeId, &UA_NODEID_NULL))
            return true;

        /* Ignore if that is configured */
        if(server->bootstrapNS0 ||
           server->config.allowEmptyVariables == UA_RULEHANDLING_ACCEPT)
            return true;

        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "Only Variables with data type BaseDataType "
                            "can contain an empty value");

        /* Ignore if that is configured */
        if(server->config.allowEmptyVariables == UA_RULEHANDLING_WARN)
            return true;

        /* Default handling is to abort */
        *reason = reason_EmptyType;
        return false;
    }

    /* Empty array of ExtensionObjects */
    if(UA_Variant_hasArrayType(value, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) &&
       value->arrayLength == 0) {
        /* There is no way to check type compatibility here. Leave it for the upper layers to
         * decide, if empty array is okay. */
        return true;        
    }

    /* Is the datatype compatible? */
    if(!compatibleValueDataType(server, value->type, targetDataTypeId)) {
        *reason = reason_ValueDataType;
        return false;
    }

    /* Array dimensions are checked later when writing the range */
    if(range)
        return true;

    /* See if the array dimensions match. */
    if(!compatibleValueArrayDimensions(value, targetArrayDimensionsSize,
                                       targetArrayDimensions)) {
        *reason = reason_ValueArrayDimensions;
        return false;
    }

    /* Check if the valuerank allows for the value dimension */
    if(!compatibleValueRankValue(targetValueRank, value)) {
        *reason = reason_ValueValueRank;
        return false;
    }

    return true;
}

/*****************/
/* Write Service */
/*****************/

static void
freeWrapperArray(void *app, void *context) {
    UA_free(context);
}

static void
unwrapEOArray(UA_Server *server, UA_Variant *value) {
    /* Only works on arrays of ExtensionObjects */
    if(!UA_Variant_hasArrayType(value, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) ||
       value->arrayLength == 0)
        return;

    /* All eo need to be already decoded and have the same wrapped type */
    UA_ExtensionObject *eo = (UA_ExtensionObject*)value->data;
    const UA_DataType *innerType = eo[0].content.decoded.type;
    for(size_t i = 0; i < value->arrayLength; i++) {
        if(eo[i].encoding != UA_EXTENSIONOBJECT_DECODED &&
           eo[i].encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
            return;
        if(eo[i].content.decoded.type != innerType)
            return;
    }

    /* Allocate the array for the unwrapped data. Since the adjusted value is
     * not cleaned up (only the original value), this memory is being cleaned up
     * by a delayed callback in the server after the method call has
     * finished. */
    UA_DelayedCallback *dc = (UA_DelayedCallback*)
        UA_malloc(sizeof(UA_DelayedCallback) + (value->arrayLength * innerType->memSize));
    if(!dc)
        return;

    /* Move the content */
    uintptr_t pos = ((uintptr_t)dc) + sizeof(UA_DelayedCallback);
    void *unwrappedArray = (void*)pos;
    for(size_t i = 0; i < value->arrayLength; i++) {
        memcpy((void*)pos, eo[i].content.decoded.data, innerType->memSize);
        pos += innerType->memSize;
    }

    /* Adjust the value */
    value->type = innerType;
    value->data = unwrappedArray;

    /* Add the delayed callback to free the memory of the unwrapped array */
    dc->callback = freeWrapperArray;
    dc->application = NULL;
    dc->context = dc;
    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, dc);
}

void
adjustValueType(UA_Server *server, UA_Variant *value,
                const UA_NodeId *targetDataTypeId) {
    /* If the value is empty, there is nothing we can do here */
    const UA_DataType *type = value->type;
    if(!type)
        return;

    /* The target type is already achieved. No adjustment needed. */
    if(UA_NodeId_equal(&type->typeId, targetDataTypeId))
        return;

    /* Unwrap ExtensionObject arrays if they all contain the same DataType */
    unwrapEOArray(server, value);

    /* Find the target type */
    const UA_DataType *targetType =
        UA_findDataTypeWithCustom(targetDataTypeId, server->config.customDataTypes);
    if(!targetType)
        return;

    /* Use the generic functionality shared by client and server */
    adjustType(value, targetType);
}

static UA_StatusCode
writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session,
                              UA_VariableNode *node, const UA_VariableTypeNode *type,
                              size_t arrayDimensionsSize, UA_UInt32 *arrayDimensions) {
    UA_assert(node != NULL);
    UA_assert(type != NULL);

    /* If this is a variabletype, there must be no instances or subtypes of it
     * when we do the change */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE &&
       UA_Node_hasSubTypeOrInstances(&node->head)) {
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Cannot change a variable type with existing instances");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check that the array dimensions match with the valuerank */
    if(!compatibleValueRankArrayDimensions(server, session, node->valueRank,
                                           arrayDimensionsSize)) {
        UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Cannot write the ArrayDimensions. The ValueRank does not match.");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check if the array dimensions match with the wildcards in the
     * variabletype (dimension length 0) */
    if(type->arrayDimensions &&
       !compatibleArrayDimensions(type->arrayDimensionsSize, type->arrayDimensions,
                                  arrayDimensionsSize, arrayDimensions)) {
       UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Array dimensions in the variable type do not match");
       return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check if the current value is compatible with the array dimensions */
    UA_DataValue value;
    UA_DataValue_init(&value);
    UA_StatusCode retval = readValueAttribute(server, session, node, &value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    if(value.hasValue) {
        if(!compatibleValueArrayDimensions(&value.value, arrayDimensionsSize,
                                           arrayDimensions))
            retval = UA_STATUSCODE_BADTYPEMISMATCH;
        UA_DataValue_clear(&value);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Array dimensions in the current value do not match");
            return retval;
        }
    }

    /* Ok, apply */
    UA_UInt32 *oldArrayDimensions = node->arrayDimensions;
    size_t oldArrayDimensionsSize = node->arrayDimensionsSize;
    retval = UA_Array_copy(arrayDimensions, arrayDimensionsSize,
                           (void**)&node->arrayDimensions,
                           &UA_TYPES[UA_TYPES_UINT32]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Array_delete(oldArrayDimensions, oldArrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
    node->arrayDimensionsSize = arrayDimensionsSize;
    return UA_STATUSCODE_GOOD;
}

/* Stack layout: ... | node | type */
static UA_StatusCode
writeValueRank(UA_Server *server, UA_Session *session,
               UA_VariableNode *node, const UA_VariableTypeNode *type,
               UA_Int32 valueRank) {
    UA_assert(node != NULL);
    UA_assert(type != NULL);

    UA_Int32 constraintValueRank = type->valueRank;

    /* If this is a variabletype, there must be no instances or subtypes of it
     * when we do the change */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE &&
       UA_Node_hasSubTypeOrInstances(&node->head))
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Check if the valuerank of the variabletype allows the change. */
    if(!compatibleValueRanks(valueRank, constraintValueRank))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Check if the new valuerank is compatible with the array dimensions. Use
     * the read service to handle data sources. */
    size_t arrayDims = node->arrayDimensionsSize;
    if(arrayDims == 0) {
        /* the value could be an array with no arrayDimensions defined.
           dimensions zero indicate a scalar for compatibleValueRankArrayDimensions. */
        UA_DataValue value;
        UA_DataValue_init(&value);
        UA_StatusCode retval = readValueAttribute(server, session, node, &value);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        if(!value.hasValue || !value.value.type) {
            /* no value -> apply */
            node->valueRank = valueRank;
            return UA_STATUSCODE_GOOD;
        }
        if(!UA_Variant_isScalar(&value.value))
            arrayDims = 1;
        UA_DataValue_clear(&value);
    }
    if(!compatibleValueRankArrayDimensions(server, session, valueRank, arrayDims))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* All good, apply the change */
    node->valueRank = valueRank;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeDataTypeAttribute(UA_Server *server, UA_Session *session,
                       UA_VariableNode *node, const UA_VariableTypeNode *type,
                       const UA_NodeId *dataType) {
    UA_assert(node != NULL);
    UA_assert(type != NULL);

    /* If this is a variabletype, there must be no instances or subtypes of it
       when we do the change */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE &&
       UA_Node_hasSubTypeOrInstances(&node->head))
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Does the new type match the constraints of the variabletype? */
    if(!compatibleDataTypes(server, dataType, &type->dataType))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Check if the current value would match the new type */
    UA_DataValue value;
    UA_DataValue_init(&value);
    UA_StatusCode retval = readValueAttribute(server, session, node, &value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    if(value.hasValue) {
        const char *reason; /* temp value */
        if(!compatibleValue(server, session, dataType, node->valueRank,
                            node->arrayDimensionsSize, node->arrayDimensions,
                            &value.value, NULL, &reason))
            retval = UA_STATUSCODE_BADTYPEMISMATCH;
        UA_DataValue_clear(&value);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "The current value does not match the new data type");
            return retval;
        }
    }

    /* Replace the datatype nodeid */
    UA_NodeId dtCopy = node->dataType;
    retval = UA_NodeId_copy(dataType, &node->dataType);
    if(retval != UA_STATUSCODE_GOOD) {
        node->dataType = dtCopy;
        return retval;
    }
    UA_NodeId_clear(&dtCopy);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeInternalValueAttribute(UA_DataValue *oldValue,
                            const UA_DataValue *value,
                            const UA_NumericRange *rangeptr) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(rangeptr) {
        /* Value on both sides? */
        if(value->status != oldValue->status || !value->hasValue || !oldValue->hasValue)
            return UA_STATUSCODE_BADINDEXRANGEINVALID;

        /* Make scalar a one-entry array for range matching */
        UA_Variant editableValue;
        const UA_Variant *v = &value->value;
        if(UA_Variant_isScalar(&value->value)) {
            editableValue = value->value;
            editableValue.arrayLength = 1;
            v = &editableValue;
        }

        /* Check that the type is an exact match and not only "compatible" */
        if(!oldValue->value.type || !v->type ||
           !UA_NodeId_equal(&oldValue->value.type->typeId, &v->type->typeId))
            return UA_STATUSCODE_BADTYPEMISMATCH;

        /* Write the value */
        retval = UA_Variant_setRangeCopy(&oldValue->value, v->data,
                                         v->arrayLength, *rangeptr);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;

        /* Write the status and timestamps */
        oldValue->hasStatus = value->hasStatus;
        oldValue->status = value->status;
        oldValue->hasSourceTimestamp = value->hasSourceTimestamp;
        oldValue->sourceTimestamp = value->sourceTimestamp;
        oldValue->hasSourcePicoseconds = value->hasSourcePicoseconds;
        oldValue->sourcePicoseconds = value->sourcePicoseconds;
    } else {
        UA_DataValue tmpValue = *value;

        /* If possible memcpy the new value over the old value without
         * a malloc. For this the value needs to be "pointerfree". */
        if(oldValue->hasValue && oldValue->value.type &&
           oldValue->value.type->pointerFree && value->hasValue &&
           value->value.type && value->value.type->pointerFree &&
           oldValue->value.type->memSize == value->value.type->memSize) {
            size_t oSize = 1;
            size_t vSize = 1;
            if(!UA_Variant_isScalar(&oldValue->value))
                oSize = oldValue->value.arrayLength;
            if(!UA_Variant_isScalar(&value->value))
                vSize = value->value.arrayLength;

            if(oSize == vSize &&
               oldValue->value.arrayDimensionsSize == value->value.arrayDimensionsSize) {
                /* Keep the old pointers, but adjust type and array length */
                tmpValue.value = oldValue->value;
                tmpValue.value.type = value->value.type;
                tmpValue.value.arrayLength = value->value.arrayLength;

                /* Copy the data over the old memory */
                memcpy(tmpValue.value.data, value->value.data,
                       oSize * oldValue->value.type->memSize);
                if(oldValue->value.arrayDimensionsSize > 0) /* No memcpy with NULL-ptr */
                    memcpy(tmpValue.value.arrayDimensions, value->value.arrayDimensions,
                           sizeof(UA_UInt32) * oldValue->value.arrayDimensionsSize);

                /* Set the value */
                *oldValue = tmpValue;
                return UA_STATUSCODE_GOOD;
            }
        }

        /* Make a deep copy of the value and replace when this succeeds */
        retval = UA_Variant_copy(&value->value, &tmpValue.value);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        UA_DataValue_clear(oldValue);
        *oldValue = tmpValue;
    }

    return retval;
}

static UA_StatusCode
writeNodeValueAttribute(UA_Server *server, UA_Session *session,
                        UA_VariableNode *node, const UA_DataValue *value,
                        const UA_String *indexRange) {
    UA_assert(node != NULL);
    UA_assert(session != NULL);
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Parse the range */
    UA_NumericRange range;
    range.dimensions = NULL;
    UA_NumericRange *rangeptr = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(indexRange && indexRange->length > 0) {
        retval = UA_NumericRange_parse(&range, *indexRange);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        rangeptr = &range;
    }

    /* Created a type-adjusted version */
    UA_DataValue adjustedValue = *value;

    /* Type checking. May change the type of adjustedValue */
    const char *reason;
    if(value->hasValue && value->value.type) {
        /* Try to correct the type */
        adjustValueType(server, &adjustedValue.value, &node->dataType);

        /* Check the type */
        if(!compatibleValue(server, session, &node->dataType, node->valueRank,
                            node->arrayDimensionsSize, node->arrayDimensions,
                            &adjustedValue.value, rangeptr, &reason)) {
            if(session == &server->adminSession) {
                /* If the value is written via the local API, log a warning */
                UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Writing the value of Node %N failed with the "
                               "following reason: %s", node->head.nodeId, reason);
            } else {
                /* Don't spam the logs if writing from remote failed */
                UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                     "Writing the value of Node %N failed with the "
                                     "following reason: %s", node->head.nodeId, reason);
            }
            if(rangeptr && rangeptr->dimensions != NULL)
                UA_free(rangeptr->dimensions);
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }
    /* Reject writing a null/empty value for non-nullable data types.
     * OPC UA Part 6, Table 1 defines which built-in types are non-nullable
     * (Boolean, numeric, StatusCode, enumerations). Part 4, 7.11.5 states:
     * "the Severity shall be BAD if the value is NULL for a non-nullable
     * Datatype". Without this check the node is left in a state that returns
     * BadWaitingForInitialData on subsequent reads. */
    } else if(!isNullableDataType(server, &node->dataType)) {
        if(rangeptr && rangeptr->dimensions != NULL)
            UA_free(rangeptr->dimensions);
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* If no source timestamp is defined create one here.
     * It should be created as close to the source as possible. */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE && !node->isDynamic) {
        adjustedValue.hasSourceTimestamp = false;
        adjustedValue.hasSourcePicoseconds = false;
    }

    /* Write into the different value source backends. */
    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; /* default */
    switch(node->valueSourceType) {
    case UA_VALUESOURCETYPE_EXTERNAL:
    case UA_VALUESOURCETYPE_INTERNAL: {
        UA_DataValue *oldValue = (node->valueSourceType == UA_VALUESOURCETYPE_INTERNAL) ?
            &node->valueSource.internal.value :
            (UA_DataValue*)UA_atomic_load((void**)node->valueSource.external.value);
        retval = writeInternalValueAttribute(oldValue, &adjustedValue, rangeptr);
        if(retval == UA_STATUSCODE_GOOD &&
           node->valueSource.internal.notifications.onWrite)
            node->valueSource.internal.notifications.
                onWrite(server, &session->sessionId, session->context,
                        &node->head.nodeId, node->head.context, rangeptr, &adjustedValue);
        break;
    }
    case UA_VALUESOURCETYPE_CALLBACK: {
        /* The value-pointer needs to be forwarded into the value-callback. The
         * pointer is used as the key to look up async operation entries. So we
         * make a temp copy and fill "adjustedvalue" into the value-memory. */
        UA_DataValue oldv = *value;
        UA_DataValue *editValue = (UA_DataValue*)(uintptr_t)value;
        *editValue = adjustedValue;
        if(node->valueSource.callback.write)
            retval = node->valueSource.callback.
                write(server, &session->sessionId, session->context,
                      &node->head.nodeId, node->head.context, rangeptr, value);
        *editValue = oldv; /* undo the above */
        break;
    }
    default:
        retval = UA_STATUSCODE_BADINTERNALERROR;
        break;
    }

    /* Write into the historical data backend. Not that the historical data
     * backend can be configured to "poll" data like a MonitoredItem also. */
#ifdef UA_ENABLE_HISTORIZING
    if(retval == UA_STATUSCODE_GOOD &&
       node->head.nodeClass == UA_NODECLASS_VARIABLE &&
       server->config.historyDatabase.setValue) {

        /* Some famous clients require the source timestap to properly receive
         * historical data. If missing we insert the source timestamp here. */
        if(!adjustedValue.hasSourceTimestamp) {
            adjustedValue.hasSourceTimestamp = true;
            adjustedValue.sourceTimestamp = UA_DateTime_now();
        }

        /* Forward to the callback */
        server->config.historyDatabase.
            setValue(server, server->config.historyDatabase.context,
                     &session->sessionId, session->context,
                     &node->head.nodeId, node->historizing, &adjustedValue);
    }
#endif

    /* Clean up */
    if(rangeptr && rangeptr->dimensions != NULL)
        UA_free(rangeptr->dimensions);
    return retval;
}

static UA_StatusCode
writeIsAbstract(UA_Node *node, UA_Boolean value) {
    switch(node->head.nodeClass) {
    case UA_NODECLASS_OBJECTTYPE:
        node->objectTypeNode.isAbstract = value;
        break;
    case UA_NODECLASS_REFERENCETYPE:
        node->referenceTypeNode.isAbstract = value;
        break;
    case UA_NODECLASS_VARIABLETYPE:
        node->variableTypeNode.isAbstract = value;
        break;
    case UA_NODECLASS_DATATYPE:
        node->dataTypeNode.isAbstract = value;
        break;
    default:
        return UA_STATUSCODE_BADNODECLASSINVALID;
    }
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* Write Service */
/*****************/

#define CHECK_DATATYPE_SCALAR(EXP_DT)                                   \
    if(!wvalue->value.hasValue ||                                       \
       &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type ||      \
       !UA_Variant_isScalar(&wvalue->value.value)) {                    \
        retval = UA_STATUSCODE_BADTYPEMISMATCH;                         \
        break;                                                          \
    }

#define CHECK_DATATYPE_ARRAY(EXP_DT)                                    \
    if(!wvalue->value.hasValue ||                                       \
       &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type ||      \
       UA_Variant_isScalar(&wvalue->value.value)) {                     \
        retval = UA_STATUSCODE_BADTYPEMISMATCH;                         \
        break;                                                          \
    }

#define CHECK_NODECLASS_WRITE(CLASS)                                    \
    if((node->head.nodeClass & (CLASS)) == 0) {                         \
        retval = UA_STATUSCODE_BADNODECLASSINVALID;                     \
        break;                                                          \
    }

#define CHECK_USERWRITEMASK(mask)                           \
    if(!(userWriteMask & (mask))) {                         \
        retval = UA_STATUSCODE_BADUSERACCESSDENIED;         \
        break;                                              \
    }

#define GET_NODETYPE                                    \
    type = (const UA_VariableTypeNode*)                 \
        getNodeType(server, &node->head, ~(UA_UInt32)0, \
                    UA_REFERENCETYPESET_NONE,           \
                    UA_BROWSEDIRECTION_INVALID);        \
    if(!type) {                                         \
        retval = UA_STATUSCODE_BADTYPEMISMATCH;         \
        break;                                          \
    }

/* Update a localized text. Don't touch the target if copying fails
 * (maybe due to BadOutOfMemory). */
static UA_StatusCode
updateLocalizedText(const UA_LocalizedText *source, UA_LocalizedText *target) {
    UA_LocalizedText tmp;
    UA_StatusCode retval = UA_LocalizedText_copy(source, &tmp);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_LocalizedText_clear(target);
    *target = tmp;
    return UA_STATUSCODE_GOOD;
}

/* Trigger sampling if a MonitoredItem surveils the attribute with no sampling
 * interval */
#ifdef UA_ENABLE_SUBSCRIPTIONS
static void
triggerImmediateDataChange(UA_Server *server, UA_Session *session,
                           UA_Node *node, const UA_WriteValue *wvalue) {
    UA_MonitoredItem *mon = node->head.monitoredItems;
    for(; mon != NULL; mon = mon->sampling.nodeListNext) {
        if(mon->itemToMonitor.attributeId != wvalue->attributeId)
            continue;
        /* TODO: Allow async read for datachanges */
        UA_DataValue value;
        UA_DataValue_init(&value);
        UA_Boolean done =
            ReadWithNodeMaybeAsync(node, server, session, mon->timestampsToReturn,
                                   &mon->itemToMonitor, &value);
        if(!done) {
            if(server->config.asyncOperationCancelCallback)
                server->config.asyncOperationCancelCallback(server, &value);
            value.hasStatus = true;
            value.status = UA_STATUSCODE_BADWAITINGFORRESPONSE;
        }
        UA_MonitoredItem_processSampledValue(server, mon, &value);
    }
}
#endif

/* This function implements the main part of the write service. Note that
 * &wvalue->value is used as the key to find async operation entries when they
 * are registered. So that pointer needs to be stable. */
static UA_StatusCode
copyAttributeIntoNode(UA_Server *server, UA_Session *session,
                      UA_Node *node, const UA_WriteValue *wvalue) {
    UA_assert(session != NULL);
    const void *value = wvalue->value.value.data;
    UA_UInt32 userWriteMask = getUserWriteMask(server, session, &node->head);
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    UA_LOG_TRACE_SESSION(server->config.logging, session,
                         "Write attribute %" PRIi32 " of Node %N",
                         wvalue->attributeId, node->head.nodeId);

    const UA_VariableTypeNode *type;

    switch(wvalue->attributeId) {
    case UA_ATTRIBUTEID_NODEID:
    case UA_ATTRIBUTEID_NODECLASS:
    case UA_ATTRIBUTEID_USERWRITEMASK:
    case UA_ATTRIBUTEID_USERACCESSLEVEL:
    case UA_ATTRIBUTEID_USEREXECUTABLE:
    case UA_ATTRIBUTEID_BROWSENAME: /* BrowseName is tracked in a binary tree
                                       for fast lookup */
        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
        break;
    case UA_ATTRIBUTEID_DISPLAYNAME:
        CHECK_USERWRITEMASK(UA_WRITEMASK_DISPLAYNAME);
        CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT);
        retval = UA_Node_insertOrUpdateDisplayName(node,
                                                   (const UA_LocalizedText *)value);
        break;
    case UA_ATTRIBUTEID_DESCRIPTION:
        CHECK_USERWRITEMASK(UA_WRITEMASK_DESCRIPTION);
        CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT);
        retval = UA_Node_insertOrUpdateDescription(node,
                                                   (const UA_LocalizedText *)value);
        break;
    case UA_ATTRIBUTEID_WRITEMASK:
        CHECK_USERWRITEMASK(UA_WRITEMASK_WRITEMASK);
        CHECK_DATATYPE_SCALAR(UINT32);
        node->head.writeMask = *(const UA_UInt32*)value;
        break;
    case UA_ATTRIBUTEID_ISABSTRACT:
        CHECK_USERWRITEMASK(UA_WRITEMASK_ISABSTRACT);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        retval = writeIsAbstract(node, *(const UA_Boolean*)value);
        break;
    case UA_ATTRIBUTEID_SYMMETRIC:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_SYMMETRIC);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->referenceTypeNode.symmetric = *(const UA_Boolean*)value;
        break;
    case UA_ATTRIBUTEID_INVERSENAME:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_INVERSENAME);
        CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT);
        retval = updateLocalizedText((const UA_LocalizedText *)value,
                                     &node->referenceTypeNode.inverseName);
        break;
    case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
        CHECK_USERWRITEMASK(UA_WRITEMASK_CONTAINSNOLOOPS);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->viewNode.containsNoLoops = *(const UA_Boolean*)value;
        break;
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
        CHECK_USERWRITEMASK(UA_WRITEMASK_EVENTNOTIFIER);
        CHECK_DATATYPE_SCALAR(BYTE);
        if(node->head.nodeClass == UA_NODECLASS_VIEW) {
            node->viewNode.eventNotifier = *(const UA_Byte*)value;
        } else {
            node->objectNode.eventNotifier = *(const UA_Byte*)value;
        }
        break;
    case UA_ATTRIBUTEID_VALUE:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
            /* The access to a value variable is granted via the UserAccessLevel
             * attribute (masked with the AccessLevel attribute) */
            UA_Byte accessLevel = getUserAccessLevel(server, session, &node->variableNode);
            if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) {
                retval = UA_STATUSCODE_BADUSERACCESSDENIED;
                break;
            }
            /* Writing a StatusCode different to "Good" requires the
             * StatusWrite bit (see OPC specification 10000-3: AccessLevelType;
             * https://reference.opcfoundation.org/specs/OPC-10000-3/v1.05.06/8.57)
             */
            if(   (wvalue->value.hasStatus)
               && (wvalue->value.status != UA_STATUSCODE_GOOD)) {
                accessLevel = getAccessLevel(server, session, &node->variableNode);
                if(!(accessLevel & UA_ACCESSLEVELMASK_STATUSWRITE)) {
                    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
                    break;
                }
                accessLevel = getUserAccessLevel(server, session, &node->variableNode);
                if(!(accessLevel & UA_ACCESSLEVELMASK_STATUSWRITE)) {
                    retval = UA_STATUSCODE_BADUSERACCESSDENIED;
                    break;
                }
            }
            /* Writing a SourceTimestamp different to NULL requires the
             * TimestampWrite bit (see OPC specification 10000-3:
             * AccessLevelType;
             * https://reference.opcfoundation.org/specs/OPC-10000-3/v1.05.06/8.57)
             */
            if(   (wvalue->value.hasSourceTimestamp)
               && (wvalue->value.sourceTimestamp != (UA_DateTime)(0))) {
                accessLevel = getAccessLevel(server, session, &node->variableNode);
                if(!(accessLevel & UA_ACCESSLEVELMASK_TIMESTAMPWRITE)) {
                    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
                    break;
                }
                accessLevel = getUserAccessLevel(server, session, &node->variableNode);
                if(!(accessLevel & UA_ACCESSLEVELMASK_TIMESTAMPWRITE)) {
                    retval = UA_STATUSCODE_BADUSERACCESSDENIED;
                    break;
                }
            }
        } else { /* UA_NODECLASS_VARIABLETYPE */
            CHECK_USERWRITEMASK(UA_WRITEMASK_VALUEFORVARIABLETYPE);
        }
        retval = writeNodeValueAttribute(server, session, &node->variableNode,
                                         &wvalue->value, &wvalue->indexRange);
        break;
    case UA_ATTRIBUTEID_DATATYPE:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_DATATYPE);
        CHECK_DATATYPE_SCALAR(NODEID);
        GET_NODETYPE;
        retval = writeDataTypeAttribute(server, session, &node->variableNode,
                                        type, (const UA_NodeId*)value);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)type);
        break;
    case UA_ATTRIBUTEID_VALUERANK:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_VALUERANK);
        CHECK_DATATYPE_SCALAR(INT32);
        GET_NODETYPE;
        retval = writeValueRank(server, session, &node->variableNode,
                                type, *(const UA_Int32*)value);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)type);
        break;
    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_ARRAYDIMENSIONS);
        CHECK_DATATYPE_ARRAY(UINT32);
        GET_NODETYPE;
        retval = writeArrayDimensionsAttribute(server, session, &node->variableNode,
                                               type, wvalue->value.value.arrayLength,
                                               (UA_UInt32 *)wvalue->value.value.data);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)type);
        break;
    case UA_ATTRIBUTEID_ACCESSLEVEL:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_ACCESSLEVEL);
        CHECK_DATATYPE_SCALAR(BYTE);
        node->variableNode.accessLevel = *(const UA_Byte*)value;
        break;
    case UA_ATTRIBUTEID_ACCESSLEVELEX:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_ACCESSLEVELEX);
        CHECK_DATATYPE_SCALAR(UINT32);
        node->variableNode.accessLevel = (UA_Byte)(*(const UA_UInt32*)value & 0xFF);
        break;
    case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL);
        CHECK_DATATYPE_SCALAR(DOUBLE);
        node->variableNode.minimumSamplingInterval = *(const UA_Double*)value;
        break;
    case UA_ATTRIBUTEID_HISTORIZING:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_HISTORIZING);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->variableNode.historizing = *(const UA_Boolean*)value;
        break;
    case UA_ATTRIBUTEID_EXECUTABLE:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
        CHECK_USERWRITEMASK(UA_WRITEMASK_EXECUTABLE);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->methodNode.executable = *(const UA_Boolean*)value;
        break;
    default:
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
        break;
    }

    /* Check if writing succeeded */
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "WriteRequest returned status code %s",
                            UA_StatusCode_name(retval));
        return retval;
    }

    /* Trigger MonitoredItems with no SamplingInterval */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    triggerImmediateDataChange(server, session, node, wvalue);
#endif

    return UA_STATUSCODE_GOOD;
}

UA_Boolean
Operation_Write(UA_Server *server, UA_Session *session,
                const UA_WriteValue *wv, UA_StatusCode *result) {
    UA_assert(session != NULL);
    *result = editNode(server, session, &wv->nodeId, wv->attributeId,
                       UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                       (UA_EditNodeCallback)copyAttributeIntoNode,
                       (void*)(uintptr_t)wv);
    return (*result != UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY);
}

UA_StatusCode
UA_Server_write(UA_Server *server, const UA_WriteValue *value) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    lockServer(server);
    Operation_Write(server, &server->adminSession, value, &res);
    /* If writing is async, signal that we can no longer receive the statuscode */
    if(res == UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY) {
        if(server->config.asyncOperationCancelCallback)
            server->config.asyncOperationCancelCallback(server, &value->value);
        res = UA_STATUSCODE_BADWAITINGFORRESPONSE;
    }
    unlockServer(server);
    return res;
}

/* Convenience function to be wrapped into inline functions */
static UA_StatusCode
__Server_write(UA_Server *server, const UA_NodeId *nodeId,
               const UA_AttributeId attributeId,
               const UA_DataType *attr_type, const void *attr) {
    lockServer(server);
    UA_StatusCode res = writeAttribute(server, &server->adminSession,
                                       nodeId, attributeId, attr, attr_type);
    unlockServer(server);
    return res;
}

/* Internal convenience function */
UA_StatusCode
writeAttribute(UA_Server *server, UA_Session *session,
               const UA_NodeId *nodeId, const UA_AttributeId attributeId,
               const void *attr, const UA_DataType *attr_type) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_WriteValue wvalue;
    UA_WriteValue_init(&wvalue);
    wvalue.nodeId = *nodeId;
    wvalue.attributeId = attributeId;
    wvalue.value.hasValue = true;
    if(attr_type == &UA_TYPES[UA_TYPES_VARIANT]) {
        wvalue.value.value = *(const UA_Variant*)attr;
    } else if(attr_type == &UA_TYPES[UA_TYPES_DATAVALUE]) {
        wvalue.value = *(const UA_DataValue*)attr;
    } else {
        /* hacked cast. the target WriteValue is used as const anyway */
        UA_Variant_setScalar(&wvalue.value.value,
                             (void*)(uintptr_t)attr, attr_type);
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    Operation_Write(server, session, &wvalue, &res);
    /* If writing is async, signal that we can no longer receive the statuscode */
    if(res == UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY) {
        if(server->config.asyncOperationCancelCallback)
            server->config.asyncOperationCancelCallback(server, &wvalue.value);
        res = UA_STATUSCODE_BADWAITINGFORRESPONSE;
    }
    return res;
}

UA_StatusCode
UA_Server_writeBrowseName(UA_Server *server, const UA_NodeId nodeId,
                          const UA_QualifiedName browseName) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
                          &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName);
}

UA_StatusCode
UA_Server_writeDisplayName(UA_Server *server, const UA_NodeId nodeId,
                           const UA_LocalizedText displayName) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName);
}

UA_StatusCode
UA_Server_writeDescription(UA_Server *server, const UA_NodeId nodeId,
                           const UA_LocalizedText description) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description);
}

UA_StatusCode
UA_Server_writeWriteMask(UA_Server *server, const UA_NodeId nodeId,
                         const UA_UInt32 writeMask) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
                          &UA_TYPES[UA_TYPES_UINT32], &writeMask);
}

UA_StatusCode
UA_Server_writeIsAbstract(UA_Server *server, const UA_NodeId nodeId,
                          const UA_Boolean isAbstract) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
                          &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract);
}

UA_StatusCode
UA_Server_writeInverseName(UA_Server *server, const UA_NodeId nodeId,
                           const UA_LocalizedText inverseName) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName);
}

UA_StatusCode
UA_Server_writeEventNotifier(UA_Server *server, const UA_NodeId nodeId,
                             const UA_Byte eventNotifier) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
                          &UA_TYPES[UA_TYPES_BYTE], &eventNotifier);
}

UA_StatusCode
UA_Server_writeValue(UA_Server *server, const UA_NodeId nodeId,
                     const UA_Variant value) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE,
                          &UA_TYPES[UA_TYPES_VARIANT], &value);
}

UA_StatusCode
UA_Server_writeDataValue(UA_Server *server, const UA_NodeId nodeId,
                     const UA_DataValue value) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE,
                          &UA_TYPES[UA_TYPES_DATAVALUE], &value);
}

UA_StatusCode
UA_Server_writeDataType(UA_Server *server, const UA_NodeId nodeId,
                        const UA_NodeId dataType) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_DATATYPE,
                          &UA_TYPES[UA_TYPES_NODEID], &dataType);
}

UA_StatusCode
UA_Server_writeValueRank(UA_Server *server, const UA_NodeId nodeId,
                         const UA_Int32 valueRank) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUERANK,
                          &UA_TYPES[UA_TYPES_INT32], &valueRank);
}

UA_StatusCode
UA_Server_writeArrayDimensions(UA_Server *server, const UA_NodeId nodeId,
                               const UA_Variant arrayDimensions) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
                          &UA_TYPES[UA_TYPES_VARIANT], &arrayDimensions);
}

UA_StatusCode
UA_Server_writeAccessLevel(UA_Server *server, const UA_NodeId nodeId,
                           const UA_Byte accessLevel) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
                          &UA_TYPES[UA_TYPES_BYTE], &accessLevel);
}

UA_StatusCode
UA_Server_writeAccessLevelEx(UA_Server *server, const UA_NodeId nodeId,
                             const UA_UInt32 accessLevelEx) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
                          &UA_TYPES[UA_TYPES_UINT32], &accessLevelEx);
}

UA_StatusCode
UA_Server_writeMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId,
                                       const UA_Double miniumSamplingInterval) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
                          &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval);
}

UA_StatusCode
UA_Server_writeHistorizing(UA_Server *server, const UA_NodeId nodeId,
                          const UA_Boolean historizing) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
                          &UA_TYPES[UA_TYPES_BOOLEAN], &historizing);
}

UA_StatusCode
UA_Server_writeExecutable(UA_Server *server, const UA_NodeId nodeId,
                          const UA_Boolean executable) {
    return __Server_write(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
                          &UA_TYPES[UA_TYPES_BOOLEAN], &executable);
}

#ifdef UA_ENABLE_HISTORIZING
typedef void
 (*UA_HistoryDatabase_readFunc)(UA_Server *server, void *hdbContext,
                                const UA_NodeId *sessionId, void *sessionContext,
                                const UA_RequestHeader *requestHeader,
                                const void *historyReadDetails,
                                UA_TimestampsToReturn timestampsToReturn,
                                UA_Boolean releaseContinuationPoints,
                                size_t nodesToReadSize,
                                const UA_HistoryReadValueId *nodesToRead,
                                UA_HistoryReadResponse *response,
                                void * const * const historyData);

UA_Boolean
Service_HistoryRead(UA_Server *server, UA_Session *session,
                    const UA_HistoryReadRequest *request,
                    UA_HistoryReadResponse *response) {
    UA_assert(session != NULL);
    UA_LOCK_ASSERT(&server->serviceMutex);
    if(server->config.historyDatabase.context == NULL) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED;
        return true;
    }

    if(request->historyReadDetails.encoding != UA_EXTENSIONOBJECT_DECODED) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED;
        return true;
    }

    const UA_DataType *historyDataType = &UA_TYPES[UA_TYPES_HISTORYDATA];
    UA_HistoryDatabase_readFunc readHistory = NULL;
    if(request->historyReadDetails.content.decoded.type ==
       &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS]) {
        UA_ReadRawModifiedDetails *details = (UA_ReadRawModifiedDetails*)
            request->historyReadDetails.content.decoded.data;
        if(!details->isReadModified) {
            readHistory = (UA_HistoryDatabase_readFunc)
                server->config.historyDatabase.readRaw;
        } else {
            historyDataType = &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA];
            readHistory = (UA_HistoryDatabase_readFunc)
                server->config.historyDatabase.readModified;
        }
    } else if(request->historyReadDetails.content.decoded.type ==
              &UA_TYPES[UA_TYPES_READEVENTDETAILS]) {
        historyDataType = &UA_TYPES[UA_TYPES_HISTORYEVENT];
        readHistory = (UA_HistoryDatabase_readFunc)
            server->config.historyDatabase.readEvent;
    } else if(request->historyReadDetails.content.decoded.type ==
              &UA_TYPES[UA_TYPES_READPROCESSEDDETAILS]) {
        readHistory = (UA_HistoryDatabase_readFunc)
            server->config.historyDatabase.readProcessed;
    } else if(request->historyReadDetails.content.decoded.type ==
              &UA_TYPES[UA_TYPES_READATTIMEDETAILS]) {
        readHistory = (UA_HistoryDatabase_readFunc)
            server->config.historyDatabase.readAtTime;
    } else {
        /* TODO handle more request->historyReadDetails.content.decoded.type types */
        response->responseHeader.serviceResult = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
        return true;
    }

    /* Check if the configured History-Backend supports the requested history type */
    if(!readHistory) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "The configured HistoryBackend does not support the selected history-type");
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED;
        return true;
    }

    /* Something to do? */
    if(request->nodesToReadSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return true;
    }

    /* Check if there are too many operations */
    if(server->config.maxNodesPerRead != 0 &&
       request->nodesToReadSize > server->config.maxNodesPerRead) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    /* Allocate a temporary array to forward the result pointers to the
     * backend */
    void **historyData = (void **)
        UA_calloc(request->nodesToReadSize, sizeof(void*));
    if(!historyData) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }

    /* Allocate the results array */
    response->results = (UA_HistoryReadResult*)
        UA_Array_new(request->nodesToReadSize, &UA_TYPES[UA_TYPES_HISTORYREADRESULT]);
    if(!response->results) {
        UA_free(historyData);
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }
    response->resultsSize = request->nodesToReadSize;

    for(size_t i = 0; i < response->resultsSize; ++i) {
        void * data = UA_new(historyDataType);
        UA_ExtensionObject_setValue(&response->results[i].historyData,
                                    data, historyDataType);
        historyData[i] = data;
    }
    readHistory(server, server->config.historyDatabase.context,
                &session->sessionId, session->context,
                &request->requestHeader,
                request->historyReadDetails.content.decoded.data,
                request->timestampsToReturn,
                request->releaseContinuationPoints,
                request->nodesToReadSize, request->nodesToRead,
                response, historyData);
    UA_free(historyData);

    return true;
}

UA_Boolean
Service_HistoryUpdate(UA_Server *server, UA_Session *session,
                      const UA_HistoryUpdateRequest *request,
                      UA_HistoryUpdateResponse *response) {
    UA_assert(session != NULL);
    UA_LOCK_ASSERT(&server->serviceMutex);

    response->resultsSize = request->historyUpdateDetailsSize;
    response->results = (UA_HistoryUpdateResult*)
        UA_Array_new(response->resultsSize, &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT]);
    if(!response->results) {
        response->resultsSize = 0;
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }

    for(size_t i = 0; i < request->historyUpdateDetailsSize; ++i) {
        UA_HistoryUpdateResult_init(&response->results[i]);
        if(request->historyUpdateDetails[i].encoding != UA_EXTENSIONOBJECT_DECODED) {
            response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
            continue;
        }

        const UA_DataType *updateDetailsType =
            request->historyUpdateDetails[i].content.decoded.type;
        void *updateDetailsData = request->historyUpdateDetails[i].content.decoded.data;

        if(updateDetailsType == &UA_TYPES[UA_TYPES_UPDATEDATADETAILS]) {
            if(!server->config.historyDatabase.updateData) {
                response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
                continue;
            }
            server->config.historyDatabase.
                updateData(server, server->config.historyDatabase.context,
                           &session->sessionId, session->context,
                           &request->requestHeader,
                           (UA_UpdateDataDetails*)updateDetailsData,
                           &response->results[i]);
            continue;
        }

        if(updateDetailsType == &UA_TYPES[UA_TYPES_DELETERAWMODIFIEDDETAILS]) {
            if(!server->config.historyDatabase.deleteRawModified) {
                response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
                continue;
            }
            server->config.historyDatabase.
                deleteRawModified(server, server->config.historyDatabase.context,
                                  &session->sessionId, session->context,
                                  &request->requestHeader,
                                  (UA_DeleteRawModifiedDetails*)updateDetailsData,
                                  &response->results[i]);
            continue;
        }

        if(updateDetailsType == &UA_TYPES[UA_TYPES_DELETEEVENTDETAILS]) {
            if(!server->config.historyDatabase.deleteEvent) {
                response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
                continue;
            }
            server->config.historyDatabase.
                deleteEvent(server, server->config.historyDatabase.context,
                            &session->sessionId, session->context,
                            &request->requestHeader,
                            (UA_DeleteEventDetails*)updateDetailsData,
                            &response->results[i]);
            continue;
        }

        response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
    }

    return true;
}

#endif

UA_StatusCode
UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
                              const UA_QualifiedName propertyName,
                              const UA_Variant value) {
    lockServer(server);
    UA_StatusCode retVal = writeObjectProperty(server, objectId, propertyName, value);
    unlockServer(server);
    return retVal;
}

UA_StatusCode
writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
                    const UA_QualifiedName propertyName,
                    const UA_Variant value) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = UA_NS0ID(HASPROPERTY);
    rpe.isInverse = false;
    rpe.includeSubtypes = false;
    rpe.targetName = propertyName;

    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = objectId;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;

    UA_StatusCode retval;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_BrowsePathResult_clear(&bpr);
        return retval;
    }

    retval = writeValueAttribute(server, bpr.targets[0].targetId.nodeId, &value);

    UA_BrowsePathResult_clear(&bpr);
    return retval;
}

UA_StatusCode
writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
                                     const UA_QualifiedName propertyName,
                                     const void *value, const UA_DataType *type) {
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setScalar(&var, (void*)(uintptr_t)value, type);
    return writeObjectProperty(server, objectId, propertyName, var);
}

UA_StatusCode UA_EXPORT
UA_Server_writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
                                     const UA_QualifiedName propertyName,
                                     const void *value, const UA_DataType *type) {
    lockServer(server);
    UA_StatusCode retval = 
        writeObjectProperty_scalar(server, objectId, propertyName, value, type);
    unlockServer(server);
    return retval;
}

static UA_LocalizedText
getLocalizedForSession(const UA_Session *session,
                       const UA_LocalizedTextListEntry *root) {
    const UA_LocalizedTextListEntry *lt;
    UA_LocalizedText result;
    UA_LocalizedText_init(&result);

    /* No session. Return the first  */
    if(!session)
        goto not_found;

    /* Exact match? */
    for(size_t i = 0; i < session->localeIdsSize; ++i) {
        for(lt = root; lt != NULL; lt = lt->next) {
            if(UA_String_equal(&session->localeIds[i], &lt->localizedText.locale))
                return lt->localizedText;
        }
    }

    /* Partial match, e.g. de-DE instead of de-CH */
    for(size_t i = 0; i < session->localeIdsSize; ++i) {
        if(session->localeIds[i].length < 2 ||
           (session->localeIdsSize > 2 &&
            session->localeIds[i].data[2] != '-'))
            continue;

        UA_String requestedPrefix;
        requestedPrefix.data = session->localeIds[i].data;
        requestedPrefix.length = 2;

        for(lt = root; lt != NULL; lt = lt->next) {
            if(lt->localizedText.locale.length < 2 ||
               (lt->localizedText.locale.length > 2 &&
                lt->localizedText.locale.data[2] != '-'))
                continue;

            UA_String currentPrefix;
            currentPrefix.data = lt->localizedText.locale.data;
            currentPrefix.length = 2;

            if(UA_String_equal(&requestedPrefix, &currentPrefix))
                return lt->localizedText;
        }
    }

    /* Not found. Return the first localized text that was added (last in the
     * linked list). Return an empty result if the list is empty. */
 not_found:
    if(!root)
        return result;
    while(root->next)
        root = root->next;
    return root->localizedText;
}

UA_LocalizedText
UA_Session_getNodeDisplayName(const UA_Session *session,
                              const UA_NodeHead *head) {
    return getLocalizedForSession(session, head->displayName);
}

UA_LocalizedText
UA_Session_getNodeDescription(const UA_Session *session,
                              const UA_NodeHead *head) {
    return getLocalizedForSession(session, head->description);
}

/**** amalgamated original file "/src/server/ua_services_discovery.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_DISCOVERY


static UA_StatusCode
setApplicationDescriptionFromRegisteredServer(const UA_FindServersRequest *request,
                                              UA_ApplicationDescription *target,
                                              const UA_RegisteredServer *rs) {
    UA_StatusCode retval =  UA_STATUSCODE_GOOD;
    target->applicationType = rs->serverType;
    retval |= UA_String_copy(&rs->serverUri, &target->applicationUri);
    retval |= UA_String_copy(&rs->productUri, &target->productUri);
    retval |= UA_String_copy(&rs->gatewayServerUri, &target->gatewayServerUri);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* If the client requests a specific locale, select the corresponding server
     * name */
    if(request->localeIdsSize) {
        UA_Boolean appNameFound = false;
        for(size_t i = 0; i < request->localeIdsSize && !appNameFound; i++) {
            for(size_t j =0; j < rs->serverNamesSize; j++) {
                if(UA_String_equal(&request->localeIds[i],
                                   &rs->serverNames[j].locale)) {
                    retval = UA_LocalizedText_copy(&rs->serverNames[j],
                                                   &target->applicationName);
                    if(retval != UA_STATUSCODE_GOOD)
                        return retval;
                    appNameFound = true;
                    break;
                }
            }
        }

        /* Server does not have the requested local, therefore we can select the
         * most suitable one */
        if(!appNameFound && rs->serverNamesSize) {
            retval = UA_LocalizedText_copy(&rs->serverNames[0],
                                           &target->applicationName);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        }
    } else if(rs->serverNamesSize) {
        /* Just take the first name */
        retval = UA_LocalizedText_copy(&rs->serverNames[0],
                                       &target->applicationName);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    /* TODO: Where do we get the discoveryProfileUri for application data? */

    if(rs->discoveryUrlsSize > 0) {
        target->discoveryUrls = (UA_String *)
            UA_calloc(rs->discoveryUrlsSize, sizeof(UA_String));
        if(!target->discoveryUrls)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        target->discoveryUrlsSize = rs->discoveryUrlsSize;
        for(size_t i = 0; i < rs->discoveryUrlsSize; i++)
            retval |= UA_String_copy(&rs->discoveryUrls[i],
                                     &target->discoveryUrls[i]);
    }

    return retval;
}
#endif

UA_Boolean
Service_FindServers(UA_Server *server, UA_Session *session,
                    const UA_FindServersRequest *request,
                    UA_FindServersResponse *response) {
    UA_ServerConfig *sc = &server->config;
    UA_LOG_DEBUG_SESSION(sc->logging, session, "Processing FindServersRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Return the server itself? */
    UA_Boolean foundSelf = false;
    if(request->serverUrisSize) {
        for(size_t i = 0; i < request->serverUrisSize; i++) {
            if(UA_String_equal(&request->serverUris[i],
                               &sc->applicationDescription.applicationUri)) {
                foundSelf = true;
                break;
            }
        }
    } else {
        foundSelf = true;
    }

#ifndef UA_ENABLE_DISCOVERY
    if(!foundSelf)
        return true;

    response->responseHeader.serviceResult =
        UA_Array_copy(&sc->applicationDescription, 1, (void**)&response->servers,
                      &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return true;

    response->serversSize = 1;
#else
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return true;
    }

    /* Allocate enough memory, including memory for the "self" response */
    size_t maxResults = dm->registeredServersSize + 1;
    response->servers = (UA_ApplicationDescription*)
        UA_Array_new(maxResults, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
    if(!response->servers) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }

    size_t pos = 0;
    registeredServer *current;

    /* Copy "self" ApplicationDescriptions into the response */
    if(foundSelf) {
        response->responseHeader.serviceResult =
            UA_ApplicationDescription_copy(&sc->applicationDescription,
                                           &response->servers[pos]);
        pos++;
        if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Copy registered ApplicationDescriptions into the response */
    LIST_FOREACH(current, &dm->registeredServers, pointers) {
        UA_Boolean usable = (request->serverUrisSize == 0);
        if(!usable) {
            /* If client only requested a specific set of servers */
            for(size_t i = 0; i < request->serverUrisSize; i++) {
                if(UA_String_equal(&current->registeredServer.serverUri,
                                   &request->serverUris[i])) {
                    usable = true;
                    break;
                }
            }
        }

        if(!usable)
            continue;

        response->responseHeader.serviceResult |=
            setApplicationDescriptionFromRegisteredServer(request,
                                                          &response->servers[pos],
                                                          &current->registeredServer);
        pos++;
    }

 cleanup:

    /* Set the final size */
    if(pos == 0) {
        UA_free(response->servers);
        response->servers = NULL;
    }
    response->serversSize = pos;
#endif

    /* Mirror back the expected EndpointUrl */
    if(request->endpointUrl.length > 0) {
        for(size_t i = 0; i < response->serversSize; i++) {
            UA_ApplicationDescription *ad = &response->servers[i];
            UA_Array_delete(ad->discoveryUrls, ad->discoveryUrlsSize,
                            &UA_TYPES[UA_TYPES_STRING]);
            ad->discoveryUrls = NULL;
            ad->discoveryUrlsSize = 0;
            response->responseHeader.serviceResult =
                UA_Array_copy(&request->endpointUrl, 1,
                              (void**)&ad->discoveryUrls,
                              &UA_TYPES[UA_TYPES_STRING]);
            if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
                break;
            ad->discoveryUrlsSize = 1;
        }
    }

    return true;
}

#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
/* All filter criteria must be fulfilled in the list entry. The comparison is
 * case insensitive. Returns true if the entry matches the filter. */
static UA_Boolean
entryMatchesCapabilityFilter(size_t serverCapabilityFilterSize,
                             UA_String *serverCapabilityFilter,
                             UA_ServerOnNetwork *current) {
    /* If the entry has less capabilities defined than the filter, there's no match */
    if(serverCapabilityFilterSize > current->serverCapabilitiesSize)
        return false;
    for(size_t i = 0; i < serverCapabilityFilterSize; i++) {
        UA_Boolean capabilityFound = false;
        for(size_t j = 0; j < current->serverCapabilitiesSize; j++) {
            if(UA_String_equal_ignorecase(&serverCapabilityFilter[i],
                               &current->serverCapabilities[j])) {
                capabilityFound = true;
                break;
            }
        }
        if(!capabilityFound)
            return false;
    }
    return true;
}

UA_Boolean
Service_FindServersOnNetwork(UA_Server *server, UA_Session *session,
                             const UA_FindServersOnNetworkRequest *request,
                             UA_FindServersOnNetworkResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return true;
    }

    if(!server->config.mdnsEnabled) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
        return true;
    }

    /* Set LastCounterResetTime */
    response->lastCounterResetTime =
        UA_DiscoveryManager_getServerOnNetworkCounterResetTime(dm);

    /* Compute the max number of records to return */
    UA_UInt32 recordCount = 0;
    UA_UInt32 serverOnNetworkRecordIdCounter =
        UA_DiscoveryManager_getServerOnNetworkRecordIdCounter(dm);
    if(request->startingRecordId < serverOnNetworkRecordIdCounter)
        recordCount = serverOnNetworkRecordIdCounter - request->startingRecordId;
    if(request->maxRecordsToReturn && recordCount > request->maxRecordsToReturn)
        recordCount = UA_MIN(recordCount, request->maxRecordsToReturn);
    if(recordCount == 0) {
        response->serversSize = 0;
        return true;
    }

    /* Iterate over all records and add to filtered list */
    UA_UInt32 filteredCount = 0;
    UA_STACKARRAY(UA_ServerOnNetwork*, filtered, recordCount);
    UA_ServerOnNetwork *current = UA_DiscoveryManager_getServerOnNetworkList(dm);
    if(!current) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return true;
    }
    for(size_t i = 0; i < recordCount; i++) {
        if(filteredCount >= recordCount)
            break;
        if(current->recordId < request->startingRecordId)
            continue;
        if(!entryMatchesCapabilityFilter(request->serverCapabilityFilterSize,
                               request->serverCapabilityFilter, current))
            continue;
        filtered[filteredCount++] = current;
        current = UA_DiscoveryManager_getNextServerOnNetworkRecord(dm, current);
        if(!current)
            break;
    }

    if(filteredCount == 0)
        return true;

    /* Allocate the array for the response */
    response->servers = (UA_ServerOnNetwork*)
        UA_malloc(sizeof(UA_ServerOnNetwork)*filteredCount);
    if(!response->servers) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }
    response->serversSize = filteredCount;

    /* Copy the server names */
    for(size_t i = 0; i < filteredCount; i++) {
        UA_ServerOnNetwork_copy(filtered[i], &response->servers[filteredCount-i-1]);
    }
    return true;
}
#endif

static UA_String basic256Sha256Uri = UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");

/* Get an encrypted policy or NULL if no encrypted policy is defined */
UA_SecurityPolicy *
getDefaultEncryptedSecurityPolicy(UA_Server *server,
                                  UA_SecurityPolicyType type) {
    UA_SecurityPolicy *best = NULL;
    UA_Byte securityLevel = 0;

    (void)type;
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
        if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE)
            continue;
        /* This SecurityPolicy is used to secure a UserIdentityToken on top of a
         * #None SecureChannel (the only situation this function is called for).
         * ECC and RSA-DH policies use ephemeral key agreement that must be
         * bound to a secured SecureChannel - they must never be used to secure
         * an auth token over #None. Only the static-RSA encryption policies
         * (e.g. Basic256Sha256, Aes*_RsaOaep/RsaPss) qualify. */
        if(UA_SecurityPolicy_isEcc(sp) || UA_SecurityPolicy_isEnhancedSecurity(sp))
            continue;
        /* Return early with Basic256Sha256 when available. "Secure enough" and
         * most clients support it.*/
        if(UA_String_equal(&basic256Sha256Uri, &sp->policyUri))
            return sp;
        if(sp->securityLevel >= securityLevel) {
            best = sp;
            securityLevel = sp->securityLevel;
        }
    }
    return best;
}

static const char *securityModeStrs[4] = {"-invalid", "-none", "-sign", "-sign+encrypt"};

UA_String
securityPolicyUriPostfix(const UA_String uri) {
    if(uri.length == 0) return uri;
    for(UA_Byte *b = uri.data + uri.length - 1; b >= uri.data; b--) {
        if(*b != '#')
            continue;
        UA_String postfix = {uri.length - (size_t)(b - uri.data), b};
        return postfix;
    }
    return uri;
}

static UA_StatusCode
updateEndpointUserIdentityToken(UA_Server *server,
                                UA_SecurityPolicyType policyType,
                                UA_EndpointDescription *ed) {
    /* Don't modify the UserIdentityTokens if there are manually configured
     * entries */
    if(ed->userIdentityTokensSize > 0)
        return UA_STATUSCODE_GOOD;

    /* Copy the UserTokenPolicies from the AccessControl plugin, but only the
     * matching ones to the securityPolicyUri.
     * TODO: Different instances of the AccessControl plugin per Endpoint */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_ServerConfig *sc = &server->config;
    for(size_t i = 0; i < sc->accessControl.userTokenPoliciesSize; i++) {
        UA_UserTokenPolicy *utp = &sc->accessControl.userTokenPolicies[i];

        /* Append the UserTokenPolicy from the AccesssControl plugin */
        res = UA_Array_appendCopy((void**)&ed->userIdentityTokens,
                                  &ed->userIdentityTokensSize, utp,
                                  &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
        if(res != UA_STATUSCODE_GOOD)
            return res;

        /* Now we modify the freshly copied last entry and ignore whatever
         * SecurityPolicy was set in sc->accessControl.userTokenPolicies and
         * choose something appropriate. If empty, the SecurityPolicy of the
         * SecureChannel is used. */
        utp = &ed->userIdentityTokens[ed->userIdentityTokensSize - 1];
        UA_String_clear(&utp->securityPolicyUri);

#ifdef UA_ENABLE_ENCRYPTION
        /* Anonymous tokens don't need encryption. All other tokens require
         * encryption with the exception of Username/Password if also the
         * allowNonePolicyPassword option has been set. The same logic is used
         * in selectEndpointAndTokenPolicy (ua_services_session.c). */
        if(utp->tokenType != UA_USERTOKENTYPE_ANONYMOUS &&
           UA_String_equal(&ed->securityPolicyUri, &UA_SECURITY_POLICY_NONE_URI) &&
           (!sc->allowNonePolicyPassword || utp->tokenType != UA_USERTOKENTYPE_USERNAME)) {
            /* Use the SecurityPolicy for the SecureChannel also for the
             * username/password. Otherwise pick the "bëst" SecurityPolicÿ. */
            UA_SecurityPolicy *encSP;
            if(ed->securityMode == UA_MESSAGESECURITYMODE_NONE)
                encSP = getDefaultEncryptedSecurityPolicy(server, policyType);
            else
                encSP = getSecurityPolicyByUri(server, &ed->securityPolicyUri);
            if(!encSP) {
                /* No encrypted SecurityPolicy available */
                UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_CLIENT,
                               "Removing a UserTokenPolicy that would allow the "
                               "password to be transmitted without encryption "
                               "(Can be enabled via config->allowNonePolicyPassword)");
                UA_StatusCode res2 =
                    UA_Array_resize((void **)&ed->userIdentityTokens,
                                    &ed->userIdentityTokensSize,
                                    ed->userIdentityTokensSize - 1,
                                    &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
                (void)res2;
                continue;
            }
            res |= UA_String_copy(&encSP->policyUri, &utp->securityPolicyUri);
        }
#endif

        /* Append the SecurityMode and SecurityPolicy postfix to the PolicyId to
         * make it unique */
        UA_String postfix;
        if(utp->securityPolicyUri.length > 0)
            postfix = securityPolicyUriPostfix(utp->securityPolicyUri);
        else
            postfix = securityPolicyUriPostfix(ed->securityPolicyUri);
        size_t newLen = utp->policyId.length + postfix.length +
            strlen(securityModeStrs[ed->securityMode]);
        UA_Byte *newString = (UA_Byte*)UA_realloc(utp->policyId.data, newLen);
        if(!newString)
            continue;
        size_t pos = utp->policyId.length;
        memcpy(&newString[pos], securityModeStrs[ed->securityMode],
               strlen(securityModeStrs[ed->securityMode]));
        pos += strlen(securityModeStrs[ed->securityMode]);
        memcpy(&newString[pos], postfix.data, postfix.length);
        utp->policyId.data = newString;
        utp->policyId.length = newLen;
    }

    return res;
}

/* Also reused to create the EndpointDescription array in the
 * CreateSessionResponse */
UA_StatusCode
setCurrentEndpointsArray(UA_Server *server, const UA_String endpointUrl,
                         UA_String *profileUris, size_t profileUrisSize,
                         UA_EndpointDescription **arr, size_t *arrSize) {
    UA_ServerConfig *sc = &server->config;

    /* Clone the endpoint for each discoveryURL? */
    size_t clone_times = 1;
    if(endpointUrl.length == 0)
        clone_times = sc->applicationDescription.discoveryUrlsSize;

    /* Allocate the array */
    *arr = (UA_EndpointDescription*)
        UA_Array_new(sc->endpointsSize * clone_times,
                     &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
    if(!*arr)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    size_t pos = 0;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t j = 0; j < sc->endpointsSize; ++j) {
        const UA_EndpointDescription *ep = &sc->endpoints[j];

        /* Test if the supported binary profile shall be returned */
        UA_Boolean usable = (profileUrisSize == 0);
        if(!usable) {
            for(size_t i = 0; i < profileUrisSize; ++i) {
                if(!UA_String_equal(&profileUris[i], &ep->transportProfileUri))
                    continue;
                usable = true;
                break;
            }
        }
        if(!usable)
            continue;

        /* Get the SecurityPolicy */
        UA_SecurityPolicy *sp =
            getSecurityPolicyByUri(server, &ep->securityPolicyUri);
        if(!sp) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "GetEndpoints: Endpoint defines SecurityPolicy "
                           "%S which is not available", ep->securityPolicyUri);
            continue;
        }

        /* Copy into the results */
        for(size_t i = 0; i < clone_times; ++i) {
            /* Copy the endpoint with a current ApplicationDescription */
            UA_EndpointDescription *ed = &(*arr)[pos];
            retval |= UA_EndpointDescription_copy(&sc->endpoints[j], ed);
            UA_ApplicationDescription_clear(&ed->server);
            retval |= UA_ApplicationDescription_copy(&sc->applicationDescription,
                                                     &ed->server);

            /* Set the local certificate configured for the SecurityPolicy */
            UA_ByteString_clear(&ed->serverCertificate);
            retval |= UA_ByteString_copy(&sp->localCertificate,
                                         &ed->serverCertificate);

            /* Set the User Identity Token list from the AccessControl plugin.
             * This also selects an appropriate SecurityPolicy for the
             * AuthenticationToken. */
            retval |= updateEndpointUserIdentityToken(server, sp->policyType, ed);

            /* OPC UA Part 4 §5.4.2:
             *
             * If the endpoint uses None security but a token policy requires
             * encryption, the client needs a certificate to encrypt the token.
             * Set serverCertificate from the first token policy's encryption
             * SecurityPolicy so the client can encrypt the credential. */
            if(ed->serverCertificate.length == 0) {
                for(size_t ti = 0; ti < ed->userIdentityTokensSize; ti++) {
                    UA_UserTokenPolicy *utp = &ed->userIdentityTokens[ti];
                    if(utp->securityPolicyUri.length == 0)
                        continue;
                    UA_SecurityPolicy *encSP =
                        getSecurityPolicyByUri(server, &utp->securityPolicyUri);
                    if(!encSP || encSP->localCertificate.length == 0)
                        continue;
                    retval |= UA_ByteString_copy(&encSP->localCertificate,
                                                 &ed->serverCertificate);
                    break;
                }
            }

            /* Set the EndpointURL */
            UA_String_clear(&ed->endpointUrl);
            if(endpointUrl.length == 0) {
                retval |= UA_String_copy(&sc->applicationDescription.discoveryUrls[i],
                                         &ed->endpointUrl);
            } else {
                /* Mirror back the requested EndpointUrl and also add it to the
                 * array of discovery urls */
                retval |= UA_String_copy(&endpointUrl, &ed->endpointUrl);

                /* Check if the ServerUrl is already present in the DiscoveryUrl
                 * array */
                size_t k = 0;
                for(; k < ed->server.discoveryUrlsSize; k++) {
                    if(UA_String_equal(&ed->endpointUrl, &ed->server.discoveryUrls[k]))
                        break;
                }
                if(k == ed->server.discoveryUrlsSize) {
                    retval |= UA_Array_appendCopy((void **)&ed->server.discoveryUrls,
                                                  &ed->server.discoveryUrlsSize,
                                                  &endpointUrl,
                                                  &UA_TYPES[UA_TYPES_STRING]);
                }
            }
            if(retval != UA_STATUSCODE_GOOD)
                goto error;

            pos++;
        }
    }

    *arrSize = pos;
    return UA_STATUSCODE_GOOD;

 error:
    UA_Array_delete(*arr, sc->endpointsSize * clone_times,
                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
    *arr = NULL;
    return retval;
}

UA_Boolean
Service_GetEndpoints(UA_Server *server, UA_Session *session,
                     const UA_GetEndpointsRequest *request,
                     UA_GetEndpointsResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing GetEndpointsRequest with endpointUrl %S",
                         request->endpointUrl);

    /* If the client expects to see a specific endpointurl, mirror it back. If
     * not, clone the endpoints with the discovery url of all networklayers. */
    response->responseHeader.serviceResult =
        setCurrentEndpointsArray(server, request->endpointUrl,
                                 request->profileUris, request->profileUrisSize,
                                 &response->endpoints, &response->endpointsSize);
    return true;
}

#ifdef UA_ENABLE_DISCOVERY

static void
process_RegisterServer(UA_Server *server, UA_Session *session,
                       const UA_RequestHeader* requestHeader,
                       const UA_RegisteredServer *requestServer,
                       const size_t requestDiscoveryConfigurationSize,
                       const UA_ExtensionObject *requestDiscoveryConfiguration,
                       UA_ResponseHeader* responseHeader,
                       size_t *responseConfigurationResultsSize,
                       UA_StatusCode **responseConfigurationResults,
                       size_t *responseDiagnosticInfosSize,
                       UA_DiagnosticInfo *responseDiagnosticInfos) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm)
        return;

    UA_ServerConfig *sc = &server->config;
    if(sc->applicationDescription.applicationType != UA_APPLICATIONTYPE_DISCOVERYSERVER) {
        responseHeader->serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
        return;
    }

    /* Find the server from the request in the registered list */
    registeredServer *rs = NULL;
    LIST_FOREACH(rs, &dm->registeredServers, pointers) {
        if(UA_String_equal(&rs->registeredServer.serverUri, &requestServer->serverUri))
            break;
    }

    UA_MdnsDiscoveryConfiguration *mdnsConfig = NULL;

    const UA_String* mdnsServerName = NULL;
    if(requestDiscoveryConfigurationSize) {
        *responseConfigurationResults =
            (UA_StatusCode *)UA_Array_new(requestDiscoveryConfigurationSize,
                                          &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!(*responseConfigurationResults)) {
            responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
        *responseConfigurationResultsSize = requestDiscoveryConfigurationSize;

        for(size_t i = 0; i < requestDiscoveryConfigurationSize; i++) {
            const UA_ExtensionObject *object = &requestDiscoveryConfiguration[i];
            if(!mdnsConfig && (object->encoding == UA_EXTENSIONOBJECT_DECODED ||
                               object->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
               (object->content.decoded.type == &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION])) {
                mdnsConfig = (UA_MdnsDiscoveryConfiguration *)object->content.decoded.data;
                mdnsServerName = &mdnsConfig->mdnsServerName;
                (*responseConfigurationResults)[i] = UA_STATUSCODE_GOOD;
            } else {
                (*responseConfigurationResults)[i] = UA_STATUSCODE_BADNOTSUPPORTED;
            }
        }
    }

    if(!mdnsServerName && requestServer->serverNamesSize)
        mdnsServerName = &requestServer->serverNames[0].text;

    if(!mdnsServerName) {
        responseHeader->serviceResult = UA_STATUSCODE_BADSERVERNAMEMISSING;
        return;
    }

    if(requestServer->discoveryUrlsSize == 0) {
        responseHeader->serviceResult = UA_STATUSCODE_BADDISCOVERYURLMISSING;
        return;
    }

    if(requestServer->semaphoreFilePath.length) {
#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
        char* filePath = (char*)
            UA_malloc(sizeof(char)*requestServer->semaphoreFilePath.length+1);
        if(!filePath) {
            UA_LOG_ERROR_SESSION(sc->logging, session,
                                 "Cannot allocate memory for semaphore path. "
                                 "Out of memory.");
            responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
        memcpy(filePath, requestServer->semaphoreFilePath.data,
               requestServer->semaphoreFilePath.length );
        filePath[requestServer->semaphoreFilePath.length] = '\0';
        if(!UA_fileExists( filePath )) {
            responseHeader->serviceResult = UA_STATUSCODE_BADSEMAPHOREFILEMISSING;
            UA_free(filePath);
            return;
        }
        UA_free(filePath);
#else
        UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_CLIENT,
                       "Ignoring semaphore file path. open62541 not compiled "
                       "with UA_ENABLE_DISCOVERY_SEMAPHORE=ON");
#endif
    }

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    if(sc->mdnsEnabled) {
        for(size_t i = 0; i < requestServer->discoveryUrlsSize; i++) {
            /* create TXT if is online and first index, delete TXT if is offline
             * and last index */
            UA_Boolean updateTxt = (requestServer->isOnline && i==0) ||
                (!requestServer->isOnline && i==requestServer->discoveryUrlsSize);
            UA_Discovery_updateMdnsForDiscoveryUrl(dm, *mdnsServerName, mdnsConfig,
                                                   requestServer->discoveryUrls[i],
                                                   requestServer->isOnline, updateTxt);
        }
    }
#endif

    if(!requestServer->isOnline) {
        /* Server is shutting down. Remove it from the registered servers list */
        if(!rs) {
            /* Server not found, show warning */
            UA_LOG_WARNING_SESSION(sc->logging, session,
                                   "Could not unregister server %S. Not registered.",
                                   requestServer->serverUri);
            responseHeader->serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
            return;
        }

        if(dm->registerServerCallback)
            dm->registerServerCallback(requestServer, dm->registerServerCallbackData);

        /* Server found, remove from list */
        LIST_REMOVE(rs, pointers);
        UA_RegisteredServer_clear(&rs->registeredServer);
        UA_free(rs);
        dm->registeredServersSize--;
        responseHeader->serviceResult = UA_STATUSCODE_GOOD;
        return;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(!rs) {
        /* Server not yet registered, register it by adding it to the list */
        UA_LOG_DEBUG_SESSION(sc->logging, session,
                             "Registering new server: %S",
                             requestServer->serverUri);

        rs = (registeredServer*)UA_malloc(sizeof(registeredServer));
        if(!rs) {
            responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }

        LIST_INSERT_HEAD(&dm->registeredServers, rs, pointers);
        dm->registeredServersSize++;
    } else {
        UA_RegisteredServer_clear(&rs->registeredServer);
    }

    /* Always call the callback, if it is set. Previously we only called it if
     * it was a new register call. It may be the case that this endpoint
     * registered before, then crashed, restarts and registeres again. In that
     * case the entry is not deleted and the callback would not be called. */
    if(dm->registerServerCallback)
        dm->registerServerCallback(requestServer,
                                   dm->registerServerCallbackData);

    /* Ccopy the data from the request into the list */
    UA_EventLoop *el = sc->eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_RegisteredServer_copy(requestServer, &rs->registeredServer);
    rs->lastSeen = nowMonotonic;
    responseHeader->serviceResult = retval;
}

UA_Boolean
Service_RegisterServer(UA_Server *server, UA_Session *session,
                       const UA_RegisterServerRequest *request,
                       UA_RegisterServerResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RegisterServerRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);
    process_RegisterServer(server, session, &request->requestHeader,
                           &request->server, 0, NULL, &response->responseHeader,
                           0, NULL, 0, NULL);
    return true;
}

UA_Boolean
Service_RegisterServer2(UA_Server *server, UA_Session *session,
                        const UA_RegisterServer2Request *request,
                        UA_RegisterServer2Response *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RegisterServer2Request");
    UA_LOCK_ASSERT(&server->serviceMutex);
    process_RegisterServer(server, session, &request->requestHeader,
                           &request->server,
                           request->discoveryConfigurationSize,
                           request->discoveryConfiguration,
                           &response->responseHeader,
                           &response->configurationResultsSize,
                           &response->configurationResults,
                           &response->diagnosticInfosSize,
                           response->diagnosticInfos);
    return true;
}

#endif /* UA_ENABLE_DISCOVERY */

/**** amalgamated original file "/src/server/ua_services_subscription.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018, 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2017-2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
  *   Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

static void
setSubscriptionSettings(UA_Server *server, UA_Subscription *subscription,
                        UA_Double requestedPublishingInterval,
                        UA_UInt32 requestedLifetimeCount,
                        UA_UInt32 requestedMaxKeepAliveCount,
                        UA_UInt32 maxNotificationsPerPublish,
                        UA_Byte priority) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* re-parameterize the subscription */
    UA_BOUNDEDVALUE_SETWBOUNDS(server->config.publishingIntervalLimits,
                               requestedPublishingInterval,
                               subscription->publishingInterval);
    /* check for nan*/
    if(requestedPublishingInterval != requestedPublishingInterval)
        subscription->publishingInterval = server->config.publishingIntervalLimits.min;
    UA_BOUNDEDVALUE_SETWBOUNDS(server->config.keepAliveCountLimits,
                               requestedMaxKeepAliveCount, subscription->maxKeepAliveCount);
    UA_BOUNDEDVALUE_SETWBOUNDS(server->config.lifeTimeCountLimits,
                               requestedLifetimeCount, subscription->lifeTimeCount);
    if(subscription->lifeTimeCount < 3 * subscription->maxKeepAliveCount)
        subscription->lifeTimeCount = 3 * subscription->maxKeepAliveCount;
    subscription->notificationsPerPublish = maxNotificationsPerPublish;
    if(maxNotificationsPerPublish == 0 ||
       maxNotificationsPerPublish > server->config.maxNotificationsPerPublish)
        subscription->notificationsPerPublish = server->config.maxNotificationsPerPublish;
    subscription->priority = priority;
}

static void
notifySubscription(UA_Server *server, UA_Subscription *sub,
                   UA_ApplicationNotificationType type) {
    if(!server->config.subscriptionNotificationCallback &&
       !server->config.globalNotificationCallback)
        return;

    static UA_THREAD_LOCAL UA_KeyValuePair createSubData[8] = {
        {{0, UA_STRING_STATIC("session-id")}, {0}},
        {{0, UA_STRING_STATIC("subscription-id")}, {0}},
        {{0, UA_STRING_STATIC("publishing-interval")}, {0}},
        {{0, UA_STRING_STATIC("lifetime-count")}, {0}},
        {{0, UA_STRING_STATIC("max-keepalive-count")}, {0}},
        {{0, UA_STRING_STATIC("max-notifications-per-publish")}, {0}},
        {{0, UA_STRING_STATIC("priority")}, {0}},
        {{0, UA_STRING_STATIC("publishing-enabled")}, {0}}
    };
    UA_KeyValueMap createSubMap = {8, createSubData};

    static UA_THREAD_LOCAL UA_NodeId sessionId;
    sessionId = (sub->session) ? sub->session->sessionId : UA_NODEID_NULL;
    static UA_THREAD_LOCAL UA_Boolean enabled;
    enabled = (sub->state == UA_SUBSCRIPTIONSTATE_ENABLED);

    UA_Variant_setScalar(&createSubData[0].value, &sessionId,
                         &UA_TYPES[UA_TYPES_NODEID]);
    UA_Variant_setScalar(&createSubData[1].value, &sub->subscriptionId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&createSubData[2].value, &sub->publishingInterval,
                         &UA_TYPES[UA_TYPES_DOUBLE]);
    UA_Variant_setScalar(&createSubData[3].value, &sub->lifeTimeCount,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&createSubData[4].value, &sub->maxKeepAliveCount,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&createSubData[5].value, &sub->notificationsPerPublish,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&createSubData[6].value, &sub->priority,
                         &UA_TYPES[UA_TYPES_BYTE]);
    UA_Variant_setScalar(&createSubData[7].value, &enabled,
                         &UA_TYPES[UA_TYPES_BOOLEAN]);

    if(server->config.subscriptionNotificationCallback)
        server->config.subscriptionNotificationCallback(server, type, createSubMap);
    if(server->config.globalNotificationCallback)
        server->config.globalNotificationCallback(server, type, createSubMap);
}

UA_Boolean
Service_CreateSubscription(UA_Server *server, UA_Session *session,
                           const UA_CreateSubscriptionRequest *request,
                           UA_CreateSubscriptionResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check limits for the number of subscriptions */
    if(((server->config.maxSubscriptions != 0) &&
        (server->subscriptionsSize >= server->config.maxSubscriptions)) ||
       ((server->config.maxSubscriptionsPerSession != 0) &&
        (session->subscriptionsSize >= server->config.maxSubscriptionsPerSession))) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS;
        return true;
    }

    /* Create the subscription */
    UA_Subscription *sub = UA_Subscription_new();
    if(!sub) {
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Processing CreateSubscriptionRequest failed");
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }

    /* Set the subscription parameters */
    setSubscriptionSettings(server, sub, request->requestedPublishingInterval,
                            request->requestedLifetimeCount,
                            request->requestedMaxKeepAliveCount,
                            request->maxNotificationsPerPublish, request->priority);
    sub->subscriptionId = ++server->lastSubscriptionId;  /* Assign the SubscriptionId */

    /* Register the subscription in the server */
    LIST_INSERT_HEAD(&server->subscriptions, sub, serverListEntry);
    server->subscriptionsSize++;

    /* Update the server statistics */
    server->serverDiagnosticsSummary.currentSubscriptionCount++;
    server->serverDiagnosticsSummary.cumulatedSubscriptionCount++;

    /* Attach the Subscription to the session */
    UA_Session_attachSubscription(session, sub);

    /* Create representation in the Session object */
#ifdef UA_ENABLE_DIAGNOSTICS
    createSubscriptionObject(server, session, sub);
#endif

    /* Set the subscription state. This also registers the callback.
     * Note that also a disabled subscription publishes keepalives. */
    UA_SubscriptionState sState = (request->publishingEnabled) ?
        UA_SUBSCRIPTIONSTATE_ENABLED : UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH;
    UA_StatusCode res = Subscription_setState(server, sub, sState);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_DEBUG_SESSION(server->config.logging, sub->session,
                             "Subscription %" PRIu32 " | Could not register "
                             "publish callback with error code %s",
                             sub->subscriptionId, UA_StatusCode_name(res));
        response->responseHeader.serviceResult = res;
        UA_Subscription_delete(server, sub);
        return true;
    }

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                             "Subscription created (Publishing interval %.2fms, "
                             "max %lu notifications per publish)",
                             sub->publishingInterval,
                             (long unsigned)sub->notificationsPerPublish);

    /* Notify the application */
    notifySubscription(server, sub,
                       UA_APPLICATIONNOTIFICATIONTYPE_SUBSCRIPTION_CREATED);

    /* Prepare the response */
    response->subscriptionId = sub->subscriptionId;
    response->revisedPublishingInterval = sub->publishingInterval;
    response->revisedLifetimeCount = sub->lifeTimeCount;
    response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount;

    return true;
}

UA_Boolean
Service_ModifySubscription(UA_Server *server, UA_Session *session,
                           const UA_ModifySubscriptionRequest *request,
                           UA_ModifySubscriptionResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing ModifySubscriptionRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return true;
    }

    /* Store the old publishing interval */
    UA_Double oldPublishingInterval = sub->publishingInterval;
    UA_Byte oldPriority = sub->priority;

    /* Change the Subscription settings */
    setSubscriptionSettings(server, sub, request->requestedPublishingInterval,
                            request->requestedLifetimeCount,
                            request->requestedMaxKeepAliveCount,
                            request->maxNotificationsPerPublish, request->priority);

    /* Reset the subscription lifetime */
    Subscription_resetLifetime(sub);

    /* The publish interval has changed */
    if(sub->publishingInterval != oldPublishingInterval) {
        /* Change the repeated callback to the new interval. This cannot fail as
         * memory is reused. */
        if(sub->publishCallbackId > 0)
            changeRepeatedCallbackInterval(server, sub->publishCallbackId,
                                           sub->publishingInterval);

        /* For each MonitoredItem check if it was/shall be attached to the
         * publish interval. This ensures that we have less cyclic callbacks
         * registered and that the notifications are fresh. */
        UA_MonitoredItem *mon;
        LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
            if(mon->parameters.samplingInterval == sub->publishingInterval ||
               mon->parameters.samplingInterval == oldPublishingInterval) {
                UA_MonitoredItem_unregisterSampling(server, mon);
                UA_MonitoredItem_registerSampling(server, mon);
            }
        }
    }

    /* If the priority has changed, re-enter the subscription to the
     * priority-ordered queue in the session. */
    if(oldPriority != sub->priority) {
        UA_Session_detachSubscription(server, session, sub, false);
        UA_Session_attachSubscription(session, sub);
    }

    /* Notify the application */
    notifySubscription(server, sub,
                       UA_APPLICATIONNOTIFICATIONTYPE_SUBSCRIPTION_MODIFIED);

    /* Set the response */
    response->revisedPublishingInterval = sub->publishingInterval;
    response->revisedLifetimeCount = sub->lifeTimeCount;
    response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount;

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->modifyCount++;
#endif

    return true;
}

static void
Operation_SetPublishingMode(UA_Server *server, UA_Session *session,
                            const UA_Boolean *publishingEnabled,
                            const UA_UInt32 *subscriptionId,
                            UA_StatusCode *result) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId);
    if(!sub) {
        *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Enable/disable */
    UA_SubscriptionState sState = (*publishingEnabled) ?
        UA_SUBSCRIPTIONSTATE_ENABLED : UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH;
    *result = Subscription_setState(server, sub, sState);

    /* Reset the lifetime counter */
    Subscription_resetLifetime(sub);

    /* Notify the application */
    notifySubscription(server, sub,
                       UA_APPLICATIONNOTIFICATIONTYPE_SUBSCRIPTION_PUBLISHINGMODE);
}

UA_Boolean
Service_SetPublishingMode(UA_Server *server, UA_Session *session,
                          const UA_SetPublishingModeRequest *request,
                          UA_SetPublishingModeResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing SetPublishingModeRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_Boolean publishingEnabled = request->publishingEnabled; /* request is const */
    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_SetPublishingMode,
                                      &publishingEnabled, &request->subscriptionIdsSize,
                                      &UA_TYPES[UA_TYPES_UINT32], &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_STATUSCODE]);

    return true;
}

UA_Boolean
Service_Publish(UA_Server *server, UA_Session *session,
                const UA_PublishRequest *request,
                UA_PublishResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing PublishRequest with RequestId %u",
                         server->asyncManager.currentRequestId);
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Return an error if the session has no subscription */
    if(TAILQ_EMPTY(&session->subscriptions)) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION;
        return true;
    }

    /* Handle too many subscriptions to free resources before trying to allocate
     * resources for the new publish request. If the limit has been reached the
     * oldest publish request are returned with an error message. */
    UA_Session_ensurePublishQueueSpace(server, session);

    /* Allocate the response to store it in the retransmission queue */
    UA_PublishResponseEntry *entry = (UA_PublishResponseEntry *)
        UA_malloc(sizeof(UA_PublishResponseEntry));
    if(!entry) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return true;
    }

    /* Prepare the response */
    UA_PublishResponse *entry_response = &entry->response;
    UA_PublishResponse_init(entry_response);

    /* Allocate the results array to acknowledge the acknowledge */
    if(request->subscriptionAcknowledgementsSize > 0) {
        entry_response->results = (UA_StatusCode *)
            UA_Array_new(request->subscriptionAcknowledgementsSize,
                         &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!entry_response->results) {
            UA_free(entry);
            response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return true;
        }
        entry_response->resultsSize = request->subscriptionAcknowledgementsSize;
    }

    /* <--- Async response from here on ---> */

    entry->requestId = server->asyncManager.currentRequestId;
    entry_response->responseHeader.requestHandle = request->requestHeader.requestHandle;

    /* Delete Acknowledged Subscription Messages */
    for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; ++i) {
        UA_SubscriptionAcknowledgement *ack = &request->subscriptionAcknowledgements[i];
        UA_Subscription *sub = UA_Session_getSubscriptionById(session, ack->subscriptionId);
        if(!sub) {
            entry_response->results[i] = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "Cannot process acknowledgements subscription %u" PRIu32,
                                 ack->subscriptionId);
            continue;
        }
        /* Remove the acked transmission from the retransmission queue */
        entry_response->results[i] =
            UA_Subscription_removeRetransmissionMessage(sub, ack->sequenceNumber);
    }

    /* Set the maxTime if a timeout hint is defined */
    entry->maxTime = UA_INT64_MAX;
    if(request->requestHeader.timeoutHint > 0) {
        UA_EventLoop *el = server->config.eventLoop;
        entry->maxTime = el->dateTime_nowMonotonic(el) +
            (request->requestHeader.timeoutHint * UA_DATETIME_MSEC);
    }

    /* Queue the publish response. It will be dequeued in a repeated publish
     * callback. This can also be triggered right now for a late
     * subscription. */
    UA_Session_queuePublishReq(session, entry, false);
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Queued a publication message");

    /* If there are late subscriptions, the new publish request is used to
     * answer them immediately. Late subscriptions with higher priority are
     * considered earlier. However, a single subscription that generates many
     * notifications must not "starve" other late subscriptions. Hence we move
     * it to the end of the queue for the subscriptions of that priority. */
    UA_Subscription *late, *late_tmp;
    TAILQ_FOREACH_SAFE(late, &session->subscriptions, sessionListEntry, late_tmp) {
        /* Skip non-late subscriptions */
        if(!late->late)
            continue;

        /* Call publish on the late subscription */
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, late,
                                  "Send PublishResponse on a late subscription");
        UA_Subscription_publish(server, late);

        /* Skip re-insert if the subscription was deleted or deactivated during
         * _publish */
        if(late->state >= UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH) {
            /* Find the first element with smaller priority and insert before
             * that. If there is none, insert at the end of the queue. */
            UA_Subscription *after = TAILQ_NEXT(late, sessionListEntry);
            while(after && after->priority >= late->priority)
                after = TAILQ_NEXT(after, sessionListEntry);
            TAILQ_REMOVE(&session->subscriptions, late, sessionListEntry);
            if(after)
                TAILQ_INSERT_BEFORE(after, late, sessionListEntry);
            else
                TAILQ_INSERT_TAIL(&session->subscriptions, late, sessionListEntry);
        }

        /* Responses left in the queue? */
        if(session->responseQueueSize == 0)
            break;
    }

    return false;
}

static void
Operation_DeleteSubscription(UA_Server *server, UA_Session *session, void *_,
                             const UA_UInt32 *subscriptionId, UA_StatusCode *result) {
    /* Find the Subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId);
    if(!sub) {
        *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Deleting Subscription with Id %" PRIu32
                             " failed with error code %s",
                             *subscriptionId, UA_StatusCode_name(*result));
        return;
    }

    /* Notify the application */
    notifySubscription(server, sub,
                       UA_APPLICATIONNOTIFICATIONTYPE_SUBSCRIPTION_DELETED);

    /* Delete the Subscription */
    UA_Subscription_delete(server, sub);
    *result = UA_STATUSCODE_GOOD;

    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Subscription %" PRIu32 " | Subscription deleted",
                         *subscriptionId);
}

UA_Boolean
Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
                            const UA_DeleteSubscriptionsRequest *request,
                            UA_DeleteSubscriptionsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteSubscriptionsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_DeleteSubscription,
                                      NULL, &request->subscriptionIdsSize,
                                      &UA_TYPES[UA_TYPES_UINT32], &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_STATUSCODE]);
    return true;
}

UA_Boolean
Service_Republish(UA_Server *server, UA_Session *session,
                  const UA_RepublishRequest *request,
                  UA_RepublishResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RepublishRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return true;
    }

    /* Reset the lifetime counter */
    Subscription_resetLifetime(sub);

    /* Update the subscription statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->republishRequestCount++;
#endif

    /* Find the notification in the retransmission queue  */
    UA_NotificationMessageEntry *entry;
    TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) {
        if(entry->message.sequenceNumber == request->retransmitSequenceNumber)
            break;
    }
    if(!entry) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADMESSAGENOTAVAILABLE;
        return true;
    }

    response->responseHeader.serviceResult =
        UA_NotificationMessage_copy(&entry->message, &response->notificationMessage);

    /* Update the subscription statistics for the case where we return a message */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->republishMessageCount++;
#endif

    return true;
}

static UA_StatusCode
setTransferredSequenceNumbers(const UA_Subscription *sub, UA_TransferResult *result) {
    /* Allocate memory */
    result->availableSequenceNumbers = (UA_UInt32*)
        UA_Array_new(sub->retransmissionQueueSize, &UA_TYPES[UA_TYPES_UINT32]);
    if(!result->availableSequenceNumbers)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    result->availableSequenceNumbersSize = sub->retransmissionQueueSize;

    /* Copy over the sequence numbers */
    UA_NotificationMessageEntry *entry;
    size_t i = 0;
    TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) {
        result->availableSequenceNumbers[i] = entry->message.sequenceNumber;
        i++;
    }

    UA_assert(i == result->availableSequenceNumbersSize);

    return UA_STATUSCODE_GOOD;
}

static void
Operation_TransferSubscription(UA_Server *server, UA_Session *session,
                               const UA_Boolean *sendInitialValues,
                               const UA_UInt32 *subscriptionId,
                               UA_TransferResult *result) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Get the subscription. This requires a server-wide lookup instead of the
     * usual session-wide lookup. */
    UA_Subscription *sub = getSubscriptionById(server, *subscriptionId);
    if(!sub) {
        result->statusCode = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->transferRequestCount++;
#endif

    /* Is this the same session? Return the sequence numbers and do nothing else. */
    UA_Session *oldSession = sub->session;
    if(oldSession == session) {
        result->statusCode = setTransferredSequenceNumbers(sub, result);
#ifdef UA_ENABLE_DIAGNOSTICS
        sub->transferredToSameClientCount++;
#endif
        return;
    }

    /* Check with AccessControl if the transfer is allowed */
    if(server->config.accessControl.allowTransferSubscription) {
        if(!server->config.accessControl.
           allowTransferSubscription(server, &server->config.accessControl,
                                     oldSession ? &oldSession->sessionId : NULL,
                                     oldSession ? oldSession->context : NULL,
                                     &session->sessionId, session->context)) {
            result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
    } else {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    /* Check limits for the number of subscriptions for this Session */
    if((server->config.maxSubscriptionsPerSession != 0) &&
       (session->subscriptionsSize >= server->config.maxSubscriptionsPerSession)) {
        result->statusCode = UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS;
        return;
    }

    /* Allocate memory for the new subscription */
    UA_Subscription *newSub = (UA_Subscription*)UA_malloc(sizeof(UA_Subscription));
    if(!newSub) {
        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }

    /* Set the available sequence numbers */
    result->statusCode = setTransferredSequenceNumbers(sub, result);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_free(newSub);
        return;
    }

    /* Create an identical copy of the Subscription struct. The original
     * subscription remains in place until a StatusChange notification has been
     * sent. The elements for lists and queues are moved over manually to ensure
     * that all backpointers are set correctly. */
    memcpy(newSub, sub, sizeof(UA_Subscription));

    /* Set to the same state as the original subscription */
    newSub->publishCallbackId = 0;
    result->statusCode = Subscription_setState(server, newSub, sub->state);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_Array_delete(result->availableSequenceNumbers,
                        sub->retransmissionQueueSize, &UA_TYPES[UA_TYPES_UINT32]);
        result->availableSequenceNumbers = NULL;
        result->availableSequenceNumbersSize = 0;
        UA_free(newSub);
        return;
    }

    /* <-- The point of no return --> */

    /* Mark the old subscription as transferred to prevent incorrect
     * diagnostic counter updates when it is deleted */
    sub->wasTransferred = true;

    /* Move over the MonitoredItems and adjust the backpointers */
    LIST_INIT(&newSub->monitoredItems);
    UA_MonitoredItem *mon, *mon_tmp;
    LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, mon_tmp) {
        LIST_REMOVE(mon, listEntry);
        mon->subscription = newSub;
        LIST_INSERT_HEAD(&newSub->monitoredItems, mon, listEntry);
    }
    sub->monitoredItemsSize = 0;

    /* Move over the notification queue */
    TAILQ_INIT(&newSub->notificationQueue);
    UA_Notification *nn, *nn_tmp;
    TAILQ_FOREACH_SAFE(nn, &sub->notificationQueue, subEntry, nn_tmp) {
        TAILQ_REMOVE(&sub->notificationQueue, nn, subEntry);
        TAILQ_INSERT_TAIL(&newSub->notificationQueue, nn, subEntry);
    }
    sub->notificationQueueSize = 0;
    sub->dataChangeNotifications = 0;
    sub->eventNotifications = 0;

    TAILQ_INIT(&newSub->retransmissionQueue);
    UA_NotificationMessageEntry *nme, *nme_tmp;
    TAILQ_FOREACH_SAFE(nme, &sub->retransmissionQueue, listEntry, nme_tmp) {
        TAILQ_REMOVE(&sub->retransmissionQueue, nme, listEntry);
        TAILQ_INSERT_TAIL(&newSub->retransmissionQueue, nme, listEntry);
        if(oldSession)
            oldSession->totalRetransmissionQueueSize -= 1;
        sub->retransmissionQueueSize -= 1;
    }
    UA_assert(sub->retransmissionQueueSize == 0);
    sub->retransmissionQueueSize = 0;

    /* Add to the server */
    UA_assert(newSub->subscriptionId == sub->subscriptionId);
    LIST_INSERT_HEAD(&server->subscriptions, newSub, serverListEntry);
    server->subscriptionsSize++;

    /* Attach to the session */
    UA_Session_attachSubscription(session, newSub);

    /* Notify the application */
    notifySubscription(server, newSub,
                       UA_APPLICATIONNOTIFICATIONTYPE_SUBSCRIPTION_TRANSFERRED);

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, newSub,
                             "Transferred to this Session");

    /* Set StatusChange in the original subscription and force publish. This
     * also removes the Subscription, even if there was no PublishResponse
     * queued to send a StatusChangeNotification. */
    sub->statusChange = UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED;
    UA_Subscription_publish(server, sub);

    /* Re-create notifications with the current values for the new subscription */
    if(*sendInitialValues)
        UA_Subscription_resendData(server, newSub);

    /* Do not update the statistics for the number of Subscriptions here. The
     * fact that we duplicate the subscription and move over the content is just
     * an implementtion detail.
     * server->serverDiagnosticsSummary.currentSubscriptionCount++;
     * server->serverDiagnosticsSummary.cumulatedSubscriptionCount++;
     *
     * Update the diagnostics statistics: */
#ifdef UA_ENABLE_DIAGNOSTICS
    if(oldSession &&
       UA_equal(&oldSession->clientDescription, &session->clientDescription,
                &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]))
        sub->transferredToSameClientCount++;
    else
        sub->transferredToAltClientCount++;
#endif
}

UA_Boolean
Service_TransferSubscriptions(UA_Server *server, UA_Session *session,
                              const UA_TransferSubscriptionsRequest *request,
                              UA_TransferSubscriptionsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing TransferSubscriptionsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_TransferSubscription,
                                      &request->sendInitialValues,
                                      &request->subscriptionIdsSize,
                                      &UA_TYPES[UA_TYPES_UINT32],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_TRANSFERRESULT]);
    return true;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_services_monitoreditem.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2017-2023 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2020 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Uranik, Berisha
 *    Copyright 2021 (c) Ammar, Morshed
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

#ifdef UA_ENABLE_DA

/* Translate a percentage deadband into an absolute deadband based on the
 * UARange property of the variable */
static UA_StatusCode
setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session,
                                  const UA_MonitoredItem *mon, UA_DataChangeFilter *filter) {
    /* A valid deadband? */
    if(filter->deadbandValue < 0.0 || filter->deadbandValue > 100.0)
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;

    /* Browse for the percent range */
    UA_QualifiedName qn = UA_QUALIFIEDNAME(0, "EURange");
    UA_BrowsePathResult bpr =
        browseSimplifiedBrowsePath(server, mon->itemToMonitor.nodeId, 1, &qn);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        UA_BrowsePathResult_clear(&bpr);
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
    }

    /* Read the range */
    UA_ReadValueId rvi;
    UA_ReadValueId_init(&rvi);
    rvi.nodeId = bpr.targets->targetId.nodeId;
    rvi.attributeId = UA_ATTRIBUTEID_VALUE;
    UA_DataValue rangeVal = readWithSession(server, session, &rvi,
                                            UA_TIMESTAMPSTORETURN_NEITHER);
    UA_BrowsePathResult_clear(&bpr);
    if(!UA_Variant_isScalar(&rangeVal.value) ||
       rangeVal.value.type != &UA_TYPES[UA_TYPES_RANGE]) {
        UA_DataValue_clear(&rangeVal);
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
    }

    /* Compute the abs deadband */
    UA_Range *euRange = (UA_Range*)rangeVal.value.data;
    UA_Double absDeadband = (filter->deadbandValue/100.0) * (euRange->high - euRange->low);

    UA_DataValue_clear(&rangeVal);

    /* EURange invalid or NaN? */
    if(absDeadband < 0.0 || absDeadband != absDeadband) {
        UA_DataValue_clear(&rangeVal);
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
    }

    /* Adjust the original filter */
    filter->deadbandType = UA_DEADBANDTYPE_ABSOLUTE;
    filter->deadbandValue = absDeadband;
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_DA */

UA_Boolean
Service_SetTriggering(UA_Server *server, UA_Session *session,
                      const UA_SetTriggeringRequest *request,
                      UA_SetTriggeringResponse *response) {
    /* Nothing to do? */
    if(request->linksToRemoveSize == 0 &&
       request->linksToAddSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return true;
    }

    /* Get the Subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return true;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    /* Get the MonitoredItem */
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, request->triggeringItemId);
    if(!mon) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return true;
    }

    /* Allocate the results arrays */
    if(request->linksToRemoveSize > 0) {
        response->removeResults = (UA_StatusCode*)
            UA_Array_new(request->linksToRemoveSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!response->removeResults) {
            response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return true;
        }
        response->removeResultsSize = request->linksToRemoveSize;
    }

    if(request->linksToAddSize> 0) {
        response->addResults = (UA_StatusCode*)
            UA_Array_new(request->linksToAddSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!response->addResults) {
            UA_Array_delete(response->removeResults,
                            request->linksToAddSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
            response->removeResults = NULL;
            response->removeResultsSize = 0;
            response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return true;
        }
        response->addResultsSize = request->linksToAddSize;
    }

    /* Apply the changes */
    for(size_t i = 0; i < request->linksToRemoveSize; i++)
        response->removeResults[i] =
            UA_MonitoredItem_removeLink(sub, mon, request->linksToRemove[i]);

    for(size_t i = 0; i < request->linksToAddSize; i++)
        response->addResults[i] =
            UA_MonitoredItem_addLink(sub, mon, request->linksToAdd[i]);

    return true;
}

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
static UA_StatusCode
checkEventFilterParam(UA_Server *server, UA_Session *session,
                      const UA_MonitoredItem *mon,
                      const UA_MonitoringParameters *params,
                      UA_ExtensionObject *filterResult) {
    UA_assert(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER);

    /* Correct data type? */
    if(params->filter.encoding != UA_EXTENSIONOBJECT_DECODED &&
       params->filter.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
        return UA_STATUSCODE_BADEVENTFILTERINVALID;
    if(params->filter.content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER])
        return UA_STATUSCODE_BADEVENTFILTERINVALID;

    UA_EventFilter *eventFilter = (UA_EventFilter *)params->filter.content.decoded.data;

    /* Correct number of elements? */
    if(eventFilter->selectClausesSize == 0 ||
       eventFilter->selectClausesSize > UA_EVENTFILTER_MAXSELECT)
        return UA_STATUSCODE_BADEVENTFILTERINVALID;

    /* Allow empty where clauses --> select every event */
    if(eventFilter->whereClause.elementsSize > UA_EVENTFILTER_MAXELEMENTS)
        return UA_STATUSCODE_BADEVENTFILTERINVALID;

    /* Check where-clause */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_ContentFilter *cf = &eventFilter->whereClause;
    UA_ContentFilterElementResult whereRes[UA_EVENTFILTER_MAXELEMENTS];
    for(size_t i = 0; i < cf->elementsSize; ++i) {
        UA_ContentFilterElement *ef = &cf->elements[i];
        whereRes[i] = UA_ContentFilterElementValidation(server, i, cf->elementsSize, ef);
        if(whereRes[i].statusCode != UA_STATUSCODE_GOOD && res == UA_STATUSCODE_GOOD)
            res = whereRes[i].statusCode;
    }

    /* Check select clause */
    UA_StatusCode selectRes[UA_EVENTFILTER_MAXSELECT];
    for(size_t i = 0; i < eventFilter->selectClausesSize; i++) {
        const UA_SimpleAttributeOperand *sao = &eventFilter->selectClauses[i];
        selectRes[i] = UA_SimpleAttributeOperandValidation(server, sao);
        if(selectRes[i] != UA_STATUSCODE_GOOD && res == UA_STATUSCODE_GOOD)
            res = selectRes[i];
    }

    /* Filter bad, return details */
    if(res != UA_STATUSCODE_GOOD) {
        UA_EventFilterResult *efr = UA_EventFilterResult_new();
        if(!efr) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
        } else {
            UA_EventFilterResult tmp_efr;
            UA_EventFilterResult_init(&tmp_efr);
            tmp_efr.selectClauseResultsSize = eventFilter->selectClausesSize;
            tmp_efr.selectClauseResults = selectRes;
            tmp_efr.whereClauseResult.elementResultsSize = cf->elementsSize;
            tmp_efr.whereClauseResult.elementResults = whereRes;
            UA_EventFilterResult_copy(&tmp_efr, efr);
            UA_ExtensionObject_setValue(filterResult, efr,
                                        &UA_TYPES[UA_TYPES_EVENTFILTERRESULT]);
        }
    }

    for(size_t i = 0; i < cf->elementsSize; ++i)
        UA_ContentFilterElementResult_clear(&whereRes[i]);
    return res;
}
#endif

UA_Boolean
VariableNode_externalDataSource(const UA_VariableNode *vn) {
    switch(vn->valueSourceType) {
    case UA_VALUESOURCETYPE_INTERNAL:
        return (vn->valueSource.internal.notifications.onRead != NULL);
    case UA_VALUESOURCETYPE_EXTERNAL:
    case UA_VALUESOURCETYPE_CALLBACK:
    default:
        return true;
    }
}

/* Verify and adjust the parameters of a MonitoredItem */
static UA_StatusCode
checkAdjustMonitoredItemParams(UA_Server *server, UA_Session *session,
                               const UA_MonitoredItem *mon,
                               const UA_DataType* valueType,
                               UA_MonitoringParameters *params,
                               UA_ExtensionObject *filterResult) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check the filter */
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        /* Event MonitoredItems need a filter */
#ifndef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        return UA_STATUSCODE_BADNOTSUPPORTED;
#else
        UA_StatusCode res =
            checkEventFilterParam(server, session, mon, params, filterResult);
        if(res != UA_STATUSCODE_GOOD)
            return UA_STATUSCODE_BADEVENTFILTERINVALID;
#endif
    } else {
        /* DataChange MonitoredItem. Can be "no filter" which defaults to
         * triggering on Status and Value. */
        if(params->filter.encoding != UA_EXTENSIONOBJECT_DECODED &&
           params->filter.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE &&
           params->filter.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY)
            return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;

        /* If the filter ExtensionObject has a body, then it must be a
         * DataChangeFilter */
        if(params->filter.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY &&
           params->filter.content.decoded.type != &UA_TYPES[UA_TYPES_DATACHANGEFILTER])
            return UA_STATUSCODE_BADFILTERNOTALLOWED;

        /* Check the deadband and adjust if necessary. */
        if(params->filter.content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) {
            UA_DataChangeFilter *filter = (UA_DataChangeFilter *)
                params->filter.content.decoded.data;
            switch(filter->deadbandType) {
            case UA_DEADBANDTYPE_NONE:
                break;
            case UA_DEADBANDTYPE_ABSOLUTE:
                if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE ||
                   !valueType || !UA_DataType_isNumeric(valueType))
                    return UA_STATUSCODE_BADFILTERNOTALLOWED;
                break;
#ifdef UA_ENABLE_DA
            case UA_DEADBANDTYPE_PERCENT: {
                if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE ||
                   !valueType || !UA_DataType_isNumeric(valueType))
                    return UA_STATUSCODE_BADFILTERNOTALLOWED;
                /* If percentage deadband is supported, look up the range values
                 * and precompute as if it was an absolute deadband. */
                UA_StatusCode res =
                    setAbsoluteFromPercentageDeadband(server, session, mon, filter);
                if(res != UA_STATUSCODE_GOOD)
                    return res;
                break;
            }
#endif
            default:
                return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
            }
        }
    }

    /* A negative number indicates that the sampling interval is the publishing
     * interval of the Subscription. Note that the sampling interval selected
     * here remains also when the Subscription's publish interval is adjusted
     * afterwards. */
    if(mon->subscription && params->samplingInterval < 0.0)
        params->samplingInterval = mon->subscription->publishingInterval;

    /* If the value comes from an "external" data source, sampling is required.
     * Otherwise, for samplingInterval == 0, we add a hook for every write. */
    UA_Boolean extValueSource = false;

    /* VariableNodes can lower-bound the permissible sampling interval */
    UA_Double minimumSamplingInterval = 0.0;

    /* Use hasValueSource and minimumSamplingInterval from a VariableNode */
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_VALUE) {
        const UA_Node *node = UA_NODESTORE_GET(server, &mon->itemToMonitor.nodeId);
        if(node) {
            if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
                minimumSamplingInterval = node->variableNode.minimumSamplingInterval;
                extValueSource = VariableNode_externalDataSource(&node->variableNode);
            }
            UA_NODESTORE_RELEASE(server, node);
        }
    }

    /* Adjust non-null sampling interval to lie within the configured limits.
     * Nodes with a value source require a >0.0 sampling interval. */
    if(params->samplingInterval != 0.0 || extValueSource) {
        UA_BOUNDEDVALUE_SETWBOUNDS(server->config.samplingIntervalLimits,
                                   params->samplingInterval, params->samplingInterval);
        /* Check for NaN */
        if(mon->parameters.samplingInterval != mon->parameters.samplingInterval)
            params->samplingInterval = server->config.samplingIntervalLimits.min;

        /* Minimum interval from the node */
        if(params->samplingInterval < minimumSamplingInterval)
            params->samplingInterval = minimumSamplingInterval;
    }

    /* Adjust the maximum queue size */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        /* 0 => Set to the configured maximum. Otherwise adjust with configured limits */
        if(params->queueSize == 0) {
            params->queueSize = server->config.queueSizeLimits.max;
        } else {
            UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits,
                                       params->queueSize, params->queueSize);
        }
    } else
#endif
    {
        /* 0 or 1 => queue-size 1. Otherwise adjust with configured limits */
        if(params->queueSize == 0)
            params->queueSize = 1;
        if(params->queueSize != 1)
            UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits,
                                       params->queueSize, params->queueSize);
    }

    return UA_STATUSCODE_GOOD;
}

static const UA_String
binaryEncoding = {sizeof("Default Binary") - 1, (UA_Byte *)"Default Binary"};

/* Structure to pass additional arguments into the operation */
struct createMonContext {
    UA_Subscription *sub;
    UA_TimestampsToReturn timestampsToReturn;
    UA_LocalMonitoredItem *localMon; /* used if non-null */
};

static void
notifyMonitoredItem(UA_Server *server, UA_MonitoredItem *mon,
                    UA_ApplicationNotificationType type) {
    /* Nothing to do? */
    if(!server->config.globalNotificationCallback &&
       !server->config.subscriptionNotificationCallback)
        return;

    /* Set up the key-value map */
    static UA_THREAD_LOCAL UA_KeyValuePair notifyMonData[13] = {
        {{0, UA_STRING_STATIC("session-id")}, {0}},
        {{0, UA_STRING_STATIC("subscription-id")}, {0}},
        {{0, UA_STRING_STATIC("monitoreditem-id")}, {0}},
        {{0, UA_STRING_STATIC("target-node")}, {0}},
        {{0, UA_STRING_STATIC("attribute-id")}, {0}},
        {{0, UA_STRING_STATIC("index-range")}, {0}},
        {{0, UA_STRING_STATIC("timestamps-to-return")}, {0}},
        {{0, UA_STRING_STATIC("monitoring-mode")}, {0}},
        {{0, UA_STRING_STATIC("client-handle")}, {0}},
        {{0, UA_STRING_STATIC("sampling-interval")}, {0}},
        {{0, UA_STRING_STATIC("filter")}, {0}},
        {{0, UA_STRING_STATIC("queue-size")}, {0}},
        {{0, UA_STRING_STATIC("discard-oldest")}, {0}},
    };
    UA_KeyValueMap notifyMonMap = {13, notifyMonData};

    UA_Subscription *sub = mon->subscription;
    UA_assert(sub); /* always defined */
    UA_NodeId sessionId = (sub->session) ? sub->session->sessionId : UA_NODEID_NULL;

    UA_Variant_setScalar(&notifyMonData[0].value, &sessionId,
                         &UA_TYPES[UA_TYPES_NODEID]);
    UA_Variant_setScalar(&notifyMonData[1].value, &sub->subscriptionId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifyMonData[2].value, &mon->monitoredItemId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifyMonData[3].value, &mon->itemToMonitor.nodeId,
                         &UA_TYPES[UA_TYPES_NODEID]);
    UA_Variant_setScalar(&notifyMonData[4].value, &mon->itemToMonitor.attributeId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifyMonData[5].value, &mon->itemToMonitor.indexRange,
                         &UA_TYPES[UA_TYPES_STRING]);
    UA_Variant_setScalar(&notifyMonData[6].value, &mon->timestampsToReturn,
                         &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN]);
    UA_Variant_setScalar(&notifyMonData[7].value, &mon->monitoringMode,
                         &UA_TYPES[UA_TYPES_MONITORINGMODE]);
    UA_Variant_setScalar(&notifyMonData[8].value, &mon->parameters.clientHandle,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifyMonData[9].value, &mon->parameters.samplingInterval,
                         &UA_TYPES[UA_TYPES_DOUBLE]);
    if(mon->parameters.filter.encoding == UA_EXTENSIONOBJECT_DECODED ||
       mon->parameters.filter.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) {
        UA_Variant_setScalar(&notifyMonData[10].value,
                             mon->parameters.filter.content.decoded.data,
                             mon->parameters.filter.content.decoded.type);
    }
    UA_Variant_setScalar(&notifyMonData[11].value, &mon->parameters.queueSize,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifyMonData[12].value, &mon->parameters.discardOldest,
                         &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* Notify the application */
    if(server->config.subscriptionNotificationCallback)
        server->config.subscriptionNotificationCallback(server, type, notifyMonMap);
    if(server->config.globalNotificationCallback)
        server->config.globalNotificationCallback(server, type, notifyMonMap);
}

static void
Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session,
                              struct createMonContext *cmc,
                              const UA_MonitoredItemCreateRequest *request,
                              UA_MonitoredItemCreateResult *result) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check available capacity */
    if(!cmc->localMon &&
       (((server->config.maxMonitoredItems != 0) &&
         (server->monitoredItemsSize >= server->config.maxMonitoredItems)) ||
        ((server->config.maxMonitoredItemsPerSubscription != 0) &&
         (cmc->sub->monitoredItemsSize >= server->config.maxMonitoredItemsPerSubscription)))) {
        result->statusCode = UA_STATUSCODE_BADTOOMANYMONITOREDITEMS;
        return;
    }

    /* Check if the encoding is supported */
    if(request->itemToMonitor.dataEncoding.name.length > 0 &&
       (!UA_String_equal(&binaryEncoding, &request->itemToMonitor.dataEncoding.name) ||
        request->itemToMonitor.dataEncoding.namespaceIndex != 0)) {
        result->statusCode = UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED;
        return;
    }

    /* Check if the encoding is set for a value */
    if(request->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE &&
       request->itemToMonitor.dataEncoding.name.length > 0) {
        result->statusCode = UA_STATUSCODE_BADDATAENCODINGINVALID;
        return;
    }

    /* Make an example read to check the itemToMonitor. The DataSource itself
     * could return a (temporary) error. This should still result in a valid
     * MonitoredItem. Only a few StatusCodes are considered unrecoverable and
     * lead to an abort:
     * - The Node does not exist
     * - The AttributeId does not match the NodeClass
     * - The Session does not have sufficient access rights
     * - The indicated encoding is not supported or not valid */
    UA_DataValue v = readWithSession(server, session, &request->itemToMonitor,
                                     cmc->timestampsToReturn);
    if(v.hasStatus &&
       (v.status == UA_STATUSCODE_BADNODEIDUNKNOWN ||
        v.status == UA_STATUSCODE_BADATTRIBUTEIDINVALID ||
        v.status == UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED ||
        v.status == UA_STATUSCODE_BADDATAENCODINGINVALID ||
        v.status == UA_STATUSCODE_BADINDEXRANGEINVALID
        /* Part 4, 5.12.2 CreateMonitoredItems: When a user adds a monitored
         * item that the user is denied read access to, the add operation for
         * the item shall succeed and the bad status Bad_NotReadable or
         * Bad_UserAccessDenied shall be returned in the Publish response.
         * v.status == UA_STATUSCODE_BADNOTREADABLE
         * v.status == UA_STATUSCODE_BADUSERACCESSDENIED
         *
         * The IndexRange error can change depending on the value.
         * v.status == UA_STATUSCODE_BADINDEXRANGENODATA */
        )) {
        result->statusCode = v.status;
        UA_DataValue_clear(&v);
        return;
    }

    /* Adding an Event MonitoredItem */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(request->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        /* If the 'SubscribeToEvents' bit of EventNotifier attribute is
         * zero, then the object cannot be subscribed to monitor events */
        if(!v.hasValue || !v.value.data) {
            result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
            UA_DataValue_clear(&v);
            return;
        }
        UA_Byte eventNotifierValue = *((UA_Byte *)v.value.data);
        if((eventNotifierValue & 0x01) != 1) {
            result->statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
            UA_LOG_INFO_SUBSCRIPTION(server->config.logging, cmc->sub,
                                     "Could not create a MonitoredItem as the "
                                     "'SubscribeToEvents' bit of the EventNotifier "
                                     "attribute is not set");
            UA_DataValue_clear(&v);
            return;
        }
    }
#endif

    const UA_DataType *valueType = v.value.type;
    UA_DataValue_clear(&v);

    /* Allocate the MonitoredItem */
    UA_MonitoredItem *newMon = NULL;
    if(cmc->localMon) {
        newMon = &cmc->localMon->monitoredItem;
        cmc->localMon = NULL; /* clean up internally from now on */
    } else {
        newMon = (UA_MonitoredItem*)UA_malloc(sizeof(UA_MonitoredItem));
        if(!newMon) {
            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
    }

    /* Initialize the MonitoredItem */
    UA_MonitoredItem_init(newMon);
    newMon->subscription = cmc->sub;
    newMon->timestampsToReturn = cmc->timestampsToReturn;
    result->statusCode |= UA_ReadValueId_copy(&request->itemToMonitor,
                                              &newMon->itemToMonitor);
    result->statusCode |= UA_MonitoringParameters_copy(&request->requestedParameters,
                                                       &newMon->parameters);
    result->statusCode |= checkAdjustMonitoredItemParams(server, session, newMon,
                                                         valueType, &newMon->parameters,
                                                         &result->filterResult);

    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_SUBSCRIPTION(server->config.logging, cmc->sub,
                                 "Could not create a MonitoredItem "
                                 "with StatusCode %s",
                                 UA_StatusCode_name(result->statusCode));
        UA_MonitoredItem_delete(server, newMon);
        return;
    }

    /* Initialize the value status so the first sample always passes the filter */
    newMon->lastValue.hasStatus = true;
    newMon->lastValue.status = ~(UA_StatusCode)0;

    /* Register the Monitoreditem in the server and subscription */
    UA_MonitoredItem_register(server, newMon);

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, cmc->sub,
                             "MonitoredItem %" PRIi32 " | "
                             "Created the MonitoredItem "
                             "(Sampling Interval: %.2fms, Queue Size: %lu)",
                             newMon->monitoredItemId,
                             newMon->parameters.samplingInterval,
                             (unsigned long)newMon->parameters.queueSize);

    /* Notify the application. Do this before setting the MonitoringMode.
     * Because this can trigger a _sample internally. */
    notifyMonitoredItem(server, newMon,
                        UA_APPLICATIONNOTIFICATIONTYPE_MONITOREDITEM_CREATED);

    /* Activate the MonitoredItem */
    result->statusCode = UA_MonitoredItem_setMonitoringMode(server, newMon,
                                                            request->monitoringMode);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        /* Notify again if the MonitoringMode could not be set */
        notifyMonitoredItem(server, newMon,
                            UA_APPLICATIONNOTIFICATIONTYPE_MONITOREDITEM_DELETE);
        UA_MonitoredItem_delete(server, newMon);
        return;
    }

    /* Prepare the response */
    result->revisedSamplingInterval = newMon->parameters.samplingInterval;
    result->revisedQueueSize = newMon->parameters.queueSize;
    result->monitoredItemId = newMon->monitoredItemId;
}

UA_Boolean
Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_CreateMonitoredItemsRequest *request,
                             UA_CreateMonitoredItemsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing CreateMonitoredItemsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check the upper bound for the number of items */
    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->itemsToCreateSize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    /* Check if the timestampstoreturn is valid */
    if(request->timestampsToReturn < UA_TIMESTAMPSTORETURN_SOURCE ||
       request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
        return true;
    }

    /* Find the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return true;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    /* Call the service */
    struct createMonContext cmc;
    cmc.timestampsToReturn = request->timestampsToReturn;
    cmc.sub = sub;
    cmc.localMon = NULL;

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_CreateMonitoredItem,
                                      &cmc, &request->itemsToCreateSize,
                                      &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]);

    return true;
}

UA_MonitoredItemCreateResult
UA_Server_createDataChangeMonitoredItem(UA_Server *server,
                                        UA_TimestampsToReturn timestampsToReturn,
                                        const UA_MonitoredItemCreateRequest item,
                                        void *monitoredItemContext,
                                        UA_Server_DataChangeNotificationCallback callback) {
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);

    /* Check that we don't use the DataChange callback for events */
    if(item.itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "DataChange-MonitoredItem cannot be created for the "
                     "EventNotifier attribute");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    /* Pre-allocate the local MonitoredItem structure */
    UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*)
        UA_calloc(1, sizeof(UA_LocalMonitoredItem));
    if(!localMon) {
        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    localMon->context = monitoredItemContext;
    localMon->callback.dataChangeCallback = callback;

    /* Call the service */
    struct createMonContext cmc;
    cmc.sub = server->adminSubscription;
    cmc.localMon = localMon;
    cmc.timestampsToReturn = timestampsToReturn;

    lockServer(server);
    Operation_CreateMonitoredItem(server, &server->adminSession, &cmc, &item, &result);
    unlockServer(server);

    /* If this failed, clean up the local MonitoredItem structure */
    if(result.statusCode != UA_STATUSCODE_GOOD && cmc.localMon)
        UA_free(localMon);

    return result;
}

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
UA_MonitoredItemCreateResult
UA_Server_createEventMonitoredItemEx(UA_Server *server,
                                     const UA_MonitoredItemCreateRequest item,
                                     void *monitoredItemContext,
                                     UA_Server_EventNotificationCallback callback) {
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);

    /* Check that we don't use the DataChange callback for events */
    if(item.itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Event-MonitoredItem must monitor the EventNotifier attribute");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    const UA_ExtensionObject *filter = &item.requestedParameters.filter;
    if((filter->encoding != UA_EXTENSIONOBJECT_DECODED &&
        filter->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       filter->content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER]) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Filter is not of EventFilter data type");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    UA_EventFilter *ef = (UA_EventFilter*)filter->content.decoded.data;
    if(ef->selectClausesSize == 0) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Event filter must define at least one select clause");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    /* Pre-allocate the local MonitoredItem structure */
    UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*)
        UA_calloc(1, sizeof(UA_LocalMonitoredItem));
    if(!localMon) {
        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    localMon->context = monitoredItemContext;
    localMon->callback.eventCallback = callback;

    /* Create the string names for the event fields */
    localMon->eventFields.map = (UA_KeyValuePair*)
        UA_calloc(ef->selectClausesSize, sizeof(UA_KeyValuePair));
    if(!localMon->eventFields.map) {
        UA_free(localMon);
        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    localMon->eventFields.mapSize = ef->selectClausesSize;

    for(size_t i = 0; i < ef->selectClausesSize; i++) {
        result.statusCode |=
            UA_SimpleAttributeOperand_print(&ef->selectClauses[i],
                                            &localMon->eventFields.map[i].key.name);
    }
    if(result.statusCode != UA_STATUSCODE_GOOD) {
        UA_KeyValueMap_clear(&localMon->eventFields);
        UA_free(localMon);
        return result;
    }

    /* Call the service */
    struct createMonContext cmc;
    cmc.sub = server->adminSubscription;
    cmc.localMon = localMon;
    cmc.timestampsToReturn = UA_TIMESTAMPSTORETURN_NEITHER;

    lockServer(server);
    Operation_CreateMonitoredItem(server, &server->adminSession, &cmc, &item, &result);
    unlockServer(server);

    /* If the service failed, clean up the local MonitoredItem structure */
    if(result.statusCode != UA_STATUSCODE_GOOD && cmc.localMon) {
        UA_KeyValueMap_clear(&localMon->eventFields);
        UA_free(localMon);
    }
    return result;
}

UA_MonitoredItemCreateResult
UA_Server_createEventMonitoredItem(UA_Server *server, const UA_NodeId nodeId,
                                   const UA_EventFilter filter, void *monitoredItemContext,
                                   UA_Server_EventNotificationCallback callback) {
    UA_MonitoredItemCreateRequest item;
    UA_MonitoredItemCreateRequest_init(&item);
    item.itemToMonitor.nodeId = nodeId;
    item.itemToMonitor.attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
    item.monitoringMode = UA_MONITORINGMODE_REPORTING;
    UA_ExtensionObject_setValue(&item.requestedParameters.filter,
                                (void*)(uintptr_t)&filter,
                                &UA_TYPES[UA_TYPES_EVENTFILTER]);
    return UA_Server_createEventMonitoredItemEx(server, item, monitoredItemContext, callback);
}
#endif

static void
Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub,
                              const UA_MonitoredItemModifyRequest *request,
                              UA_MonitoredItemModifyResult *result) {
    /* Get the MonitoredItem */
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, request->monitoredItemId);
    if(!mon) {
        result->statusCode = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return;
    }

    /* Make local copy of the settings */
    UA_MonitoringParameters params;
    result->statusCode =
        UA_MonitoringParameters_copy(&request->requestedParameters, &params);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Read the current value to test if filters are possible.
     * Can return an empty value (v.value.type == NULL). */
    UA_DataValue v = readWithSession(server, session, &mon->itemToMonitor,
                                     mon->timestampsToReturn);

    /* Verify and adjust the new parameters. This still leaves the original
     * MonitoredItem untouched. */
    result->statusCode =
        checkAdjustMonitoredItemParams(server, session, mon, v.value.type,
                                       &params, &result->filterResult);
    UA_DataValue_clear(&v);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_MonitoringParameters_clear(&params);
        return;
    }

    /* Store the old sampling interval */
    UA_Double oldSamplingInterval = mon->parameters.samplingInterval;

    /* Move over the new settings */
    UA_MonitoringParameters_clear(&mon->parameters);
    mon->parameters = params;

    /* Re-register the callback if necessary */
    if(oldSamplingInterval != mon->parameters.samplingInterval) {
        UA_MonitoredItem_unregisterSampling(server, mon);
        result->statusCode =
            UA_MonitoredItem_setMonitoringMode(server, mon, mon->monitoringMode);
    }

    result->revisedSamplingInterval = mon->parameters.samplingInterval;
    result->revisedQueueSize = mon->parameters.queueSize;

    /* If the sampling interval is negative (the sampling callback is called
     * from within the publishing callback), return the publishing interval of
     * the Subscription. Note that we only use the cyclic callback of the
     * Subscription. So if the Subscription publishing interval is modified,
     * this also impacts this MonitoredItem. */
    if(result->revisedSamplingInterval < 0.0 && mon->subscription)
        result->revisedSamplingInterval = mon->subscription->publishingInterval;

    /* Remove some notifications if the queue is now too small */
    UA_MonitoredItem_ensureQueueSpace(server, mon);

    /* Remove the overflow bits if the queue has now a size of 1 */
    UA_MonitoredItem_removeOverflowInfoBits(mon);

    /* If the sampling interval is negative (the sampling callback is called
     * from within the publishing callback), return the publishing interval of
     * the Subscription. Note that we only use the cyclic callback of the
     * Subscription. So if the Subscription publishing interval is modified,
     * this also impacts this MonitoredItem. */
    if(result->revisedSamplingInterval < 0.0 && mon->subscription)
        result->revisedSamplingInterval = mon->subscription->publishingInterval;

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                             "MonitoredItem %" PRIi32 " | "
                             "Modified the MonitoredItem "
                             "(Sampling Interval: %fms, Queue Size: %lu)",
                             mon->monitoredItemId,
                             mon->parameters.samplingInterval,
                             (unsigned long)mon->queueSize);

    notifyMonitoredItem(server, mon, UA_APPLICATIONNOTIFICATIONTYPE_MONITOREDITEM_MODIFIED);
}

UA_Boolean
Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_ModifyMonitoredItemsRequest *request,
                             UA_ModifyMonitoredItemsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing ModifyMonitoredItemsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->itemsToModifySize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    /* Check if the timestampstoreturn is valid */
    if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
        return true;
    }

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return true;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_ModifyMonitoredItem,
                                      sub, &request->itemsToModifySize,
                                      &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT]);

    return true;
}

struct setMonitoringContext {
    UA_Subscription *sub;
    UA_MonitoringMode monitoringMode;
};

static void
Operation_SetMonitoringMode(UA_Server *server, UA_Session *session,
                            struct setMonitoringContext *smc,
                            const UA_UInt32 *monitoredItemId, UA_StatusCode *result) {
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(smc->sub, *monitoredItemId);
    if(!mon) {
        *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return;
    }
    *result = UA_MonitoredItem_setMonitoringMode(server, mon, smc->monitoringMode);

    if(*result == UA_STATUSCODE_GOOD)
        notifyMonitoredItem(server, mon, UA_APPLICATIONNOTIFICATIONTYPE_MONITOREDITEM_MONITORINGMODE);
}

UA_Boolean
Service_SetMonitoringMode(UA_Server *server, UA_Session *session,
                          const UA_SetMonitoringModeRequest *request,
                          UA_SetMonitoringModeResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing SetMonitoringMode");
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check the max number if items */
    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return true;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    /* Call the service */
    struct setMonitoringContext smc;
    smc.sub = sub;
    smc.monitoringMode = request->monitoringMode;

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_SetMonitoringMode,
                                      &smc, &request->monitoredItemIdsSize,
                                      &UA_TYPES[UA_TYPES_UINT32],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_STATUSCODE]);

    return true;
}

static void
Operation_DeleteMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub,
                              const UA_UInt32 *monitoredItemId, UA_StatusCode *result) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, *monitoredItemId);
    if(!mon) {
        *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return;
    }
    notifyMonitoredItem(server, mon,
                        UA_APPLICATIONNOTIFICATIONTYPE_MONITOREDITEM_DELETE);
    UA_MonitoredItem_delete(server, mon);
}

UA_Boolean
Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_DeleteMonitoredItemsRequest *request,
                             UA_DeleteMonitoredItemsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteMonitoredItemsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return true;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_DeleteMonitoredItem,
                                      sub, &request->monitoredItemIdsSize,
                                      &UA_TYPES[UA_TYPES_UINT32],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_STATUSCODE]);

    return true;
}

UA_StatusCode
UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId) {
    lockServer(server);

    UA_Subscription *sub = server->adminSubscription;
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        if(mon->monitoredItemId == monitoredItemId)
            break;
    }

    UA_StatusCode res = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    if(mon) {
        notifyMonitoredItem(server, mon,
                            UA_APPLICATIONNOTIFICATIONTYPE_MONITOREDITEM_DELETE);
        UA_MonitoredItem_delete(server, mon);
        res = UA_STATUSCODE_GOOD;
    }

    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_services_securechannel.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2023 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Phuong Nguyen)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


/* The OpenSecureChannel Service in the server is split as follows:
 *
 * - Decode the OPN Asymmetric Header (SecureChannel)
 * - Process the OPN Asymmetric Header (here, via channel->processOPNHeader callback)
 *   - Verify the remote certificate and configure the SecureChannel
 * - Verify the OPN message signature and decrypt (SecureChannel)
 * - Process the OpenSecureChannelRequest (here, via standard service call logic)
 */

UA_StatusCode
processOPN_AsymHeader(void *application, UA_SecureChannel *channel,
                      const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
    if(channel->securityPolicy)
        return UA_STATUSCODE_GOOD;

    /* Iterate over available endpoints and choose the correct one */
    UA_Server *server = (UA_Server *)application;
    UA_ServerConfig *sc = &server->config;
    UA_SecurityPolicy *securityPolicy = NULL;
    for(size_t i = 0; i < sc->securityPoliciesSize; ++i) {
        UA_SecurityPolicy *policy = &sc->securityPolicies[i];
        if(!UA_String_equal(&asymHeader->securityPolicyUri, &policy->policyUri))
            continue;

        UA_StatusCode res = policy->
            compareCertThumbprint(policy, &asymHeader->receiverCertificateThumbprint);
        if(res != UA_STATUSCODE_GOOD)
            continue;

        /* We found the correct policy. The endpoint is selected later during
         * CreateSession. There the channel's SecurityMode also gets checked
         * against the endpoint definition. */
        securityPolicy = policy;
        break;
    }

    if(!securityPolicy)
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    /* TODO: Check the URI in the certificate */

    /* Verify the client certificate (chain).
     * Here we don't have the ApplicationDescription.
     * This check follows in the CreateSession service. */
    if(asymHeader->senderCertificate.length > 0) {
        UA_StatusCode res =
            validateCertificate(server, &sc->secureChannelPKI, channel, NULL,
                                "OpenSecureChannel", NULL, asymHeader->senderCertificate);
        UA_CHECK_STATUS(res, return res);
    }

    /* If the sender provides a chain of certificates then we shall extract the
     * ApplicationInstanceCertificate and ignore the extra bytes. See also: OPC
     * UA Part 6, V1.04, 6.7.2.3 Security Header, Table 42 - Asymmetric
     * algorithm Security header */
    UA_ByteString appInstCert = getLeafCertificate(asymHeader->senderCertificate);

    /* Create the channel context and parse the sender (remote) certificate used
     * for the secureChannel. This sets a "temporary SecurityMode" so that we
     * can properly decrypt the remaining OPN message. The final SecurityMode is
     * set in the OpenSecureChannel service. */
    return UA_SecureChannel_setSecurityPolicy(channel, securityPolicy, &appInstCert);
}

void
Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel *channel,
                          UA_OpenSecureChannelRequest *request,
                          UA_OpenSecureChannelResponse *response) {
    UA_ServerConfig *sc = &server->config;
    UA_EventLoop *el = server->config.eventLoop;
    const UA_SecurityPolicy *sp = channel->securityPolicy;

    switch(request->requestType) {
    /* Open the channel */
    case UA_SECURITYTOKENREQUESTTYPE_ISSUE: {
        /* We must expect an OPN handshake */
        if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT) {
            UA_LOG_ERROR_CHANNEL(sc->logging, channel,
                                 "OpenSecureChannel: Cannot open "
                                 "already open or closed channel");
            response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
            return;
        }

        /* Ensure the SecurityMode does not cause a wrong array access during
         * logging */
        if(request->securityMode > UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
            request->securityMode = UA_MESSAGESECURITYMODE_INVALID;

        /* Set the SecurityMode. This overwrites the "temporary SecurityMode"
         * that has been set set in UA_SecureChannel_setSecurityPolicy.*/
        response->responseHeader.serviceResult =
            UA_SecureChannel_setSecurityMode(channel, request->securityMode);
        if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CHANNEL(sc->logging, channel,
                                 "OpenSecureChannel: Client tries mismatching "
                                 "SecurityMode %s for SecurityPolicy %S",
                                 securityModeNames[request->securityMode],
                                 sp->policyUri);
            return;
        }
        break;
    }

    /* Renew the channel */
    case UA_SECURITYTOKENREQUESTTYPE_RENEW:
        /* The channel must be open to be renewed */
        if(channel->state != UA_SECURECHANNELSTATE_OPEN) {
            UA_LOG_ERROR_CHANNEL(sc->logging, channel,
                                 "OpenSecureChannel: The client called renew on "
                                 "channel which is not open");
            response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
            return;
        }

        /* Check whether the nonce was reused */
        if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE &&
           UA_ByteString_equal(&channel->remoteNonce, &request->clientNonce)) {
            UA_LOG_ERROR_CHANNEL(sc->logging, channel,
                                 "OpenSecureChannel: The client called renew "
                                 "reusing the previous nonce");
            response->responseHeader.serviceResult =
                UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            return;
        }

        break;

    /* Unknown request type */
    default:
        UA_LOG_ERROR_CHANNEL(sc->logging, channel,
                             "OpenSecureChannel: Unknown request type");
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* Create a new SecurityToken. It will be switched over when the first
     * message is received. The ChannelId is left unchanged. */
    channel->altSecurityToken.channelId = channel->securityToken.channelId;
    channel->altSecurityToken.tokenId = server->lastTokenId++;
    channel->altSecurityToken.createdAt = el->dateTime_nowMonotonic(el);
    channel->altSecurityToken.revisedLifetime =
        (request->requestedLifetime > sc->maxSecurityTokenLifetime) ?
        sc->maxSecurityTokenLifetime : request->requestedLifetime;
    if(channel->altSecurityToken.revisedLifetime == 0)
        channel->altSecurityToken.revisedLifetime =
            sc->maxSecurityTokenLifetime;

    /* Set the nonces. The remote nonce will be "rotated in" when it is first used. */
    UA_ByteString_clear(&channel->remoteNonce);
    channel->remoteNonce = request->clientNonce;
    UA_ByteString_init(&request->clientNonce);

    response->responseHeader.serviceResult = UA_SecureChannel_generateLocalNonce(channel);
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(sc->logging, channel,
                             "OpenSecureChannel: Cannot generate the local nonce");
        return;
    }

    /* Update the channel state */
    channel->renewState = UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER;
    channel->state = UA_SECURECHANNELSTATE_OPEN;

    /* Set the response */
    response->securityToken = channel->altSecurityToken;
    response->securityToken.createdAt = el->dateTime_now(el); /* only for sending */
    response->responseHeader.timestamp = response->securityToken.createdAt;
    response->responseHeader.requestHandle = request->requestHeader.requestHandle;
    response->responseHeader.serviceResult =
        UA_ByteString_copy(&channel->localNonce, &response->serverNonce);
    UA_CHECK_STATUS(response->responseHeader.serviceResult, return);

    /* Success */
    if(request->requestType == UA_SECURITYTOKENREQUESTTYPE_ISSUE) {
        UA_LOG_INFO_CHANNEL(sc->logging, channel,
                            "OpenSecureChannel: Channel opened with SecurityMode %s for "
                            "SecurityPolicy %S and a revised lifetime of %.2fs",
                            securityModeNames[channel->securityMode],
                            channel->securityPolicy->policyUri,
                            (UA_Float)response->securityToken.revisedLifetime / 1000);

        /* Notify the application about the open SecureChannel */
        notifySecureChannel(server, channel,
                            UA_APPLICATIONNOTIFICATIONTYPE_SECURECHANNEL_OPENED);
    } else {
        UA_LOG_INFO_CHANNEL(sc->logging, channel,
                            "OpenSecureChannel: Channel renewed with a revised "
                            "lifetime of %.2fs",
                            (UA_Float)response->securityToken.revisedLifetime / 1000);
    }
}

/* The server does not send a CloseSecureChannel response */
void
Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel) {
    UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
}

void
notifySecureChannel(UA_Server *server, UA_SecureChannel *channel,
                    UA_ApplicationNotificationType type) {
    UA_ServerConfig *sc = &server->config;

    /* Nothing to do? */
    if(!sc->globalNotificationCallback && !sc->secureChannelNotificationCallback)
        return;

    /* Prepare the payload */
    static UA_THREAD_LOCAL UA_KeyValuePair notifySCData[15] = {
        {{0, UA_STRING_STATIC("securechannel-id")}, {0}},
        {{0, UA_STRING_STATIC("connection-manager-name")}, {0}},
        {{0, UA_STRING_STATIC("connection-id")}, {0}},
        {{0, UA_STRING_STATIC("remote-address")}, {0}},
        {{0, UA_STRING_STATIC("protocol-version")}, {0}},
        {{0, UA_STRING_STATIC("recv-buffer-size")}, {0}},
        {{0, UA_STRING_STATIC("recv-max-message-size")}, {0}},
        {{0, UA_STRING_STATIC("recv-max-chunk-count")}, {0}},
        {{0, UA_STRING_STATIC("send-buffer-size")}, {0}},
        {{0, UA_STRING_STATIC("send-max-message-size")}, {0}},
        {{0, UA_STRING_STATIC("send-max-chunk-count")}, {0}},
        {{0, UA_STRING_STATIC("endpoint-url")}, {0}},
        {{0, UA_STRING_STATIC("security-mode")}, {0}},
        {{0, UA_STRING_STATIC("security-policy-url")}, {0}},
        {{0, UA_STRING_STATIC("remote-certificate")}, {0}}
    };
    UA_KeyValueMap notifySCMap = {15, notifySCData};

    UA_Variant_setScalar(&notifySCData[0].value, &channel->securityToken.channelId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[1].value,
                         &channel->connectionManager->eventSource.name,
                         &UA_TYPES[UA_TYPES_STRING]);
    UA_UInt64 connectionId = channel->connectionId;
    UA_Variant_setScalar(&notifySCData[2].value, &connectionId,
                         &UA_TYPES[UA_TYPES_UINT64]);
    UA_Variant_setScalar(&notifySCData[3].value, &channel->remoteAddress,
                         &UA_TYPES[UA_TYPES_STRING]);
    UA_Variant_setScalar(&notifySCData[4].value, &channel->config.protocolVersion,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[5].value, &channel->config.recvBufferSize,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[6].value, &channel->config.localMaxMessageSize,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[7].value, &channel->config.localMaxChunkCount,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[8].value, &channel->config.sendBufferSize,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[9].value, &channel->config.remoteMaxMessageSize,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[10].value, &channel->config.remoteMaxChunkCount,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&notifySCData[11].value, &channel->endpointUrl,
                         &UA_TYPES[UA_TYPES_STRING]);
    UA_Variant_setScalar(&notifySCData[12].value, &channel->securityMode,
                         &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE]);
    UA_String securityPolicyUri = UA_STRING_NULL;
    if(channel->securityPolicy)
        securityPolicyUri = channel->securityPolicy->policyUri;
    UA_Variant_setScalar(&notifySCData[13].value, &securityPolicyUri,
                         &UA_TYPES[UA_TYPES_STRING]);
    UA_Variant_setScalar(&notifySCData[14].value, &channel->remoteCertificate,
                         &UA_TYPES[UA_TYPES_BYTESTRING]);

    /* Notify the application */
    if(sc->secureChannelNotificationCallback)
        sc->secureChannelNotificationCallback(server, type, notifySCMap);
    if(sc->globalNotificationCallback)
        sc->globalNotificationCallback(server, type, notifySCMap);
}

/**** amalgamated original file "/src/server/ua_services_nodemanagement.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2016 (c) LEvertz
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Christian von Arnim
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart  (for VDW and umati)
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


/*********************/
/* Edit Node Context */
/*********************/

UA_StatusCode
UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
                         void **nodeContext) {
    lockServer(server);
    UA_StatusCode retval = getNodeContext(server, nodeId, nodeContext);
    unlockServer(server);
    return retval;
}

UA_StatusCode
getNodeContext(UA_Server *server, UA_NodeId nodeId,
               void **nodeContext) {
    const UA_Node *node = UA_NODESTORE_GET(server, &nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    *nodeContext = node->head.context;
    UA_NODESTORE_RELEASE(server, node);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setDeconstructedNode(UA_Server *server, UA_Session *session,
                     UA_NodeHead *head, void *context) {
    head->constructed = false;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setConstructedNodeContext(UA_Server *server, UA_Session *session,
                          UA_NodeHead *head, void *context) {
    head->context = context;
    head->constructed = true;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setNodeContext(UA_Server *server, UA_NodeId nodeId, void *nodeContext) {
    UA_Node *node =
        UA_NODESTORE_GET_EDIT_SELECTIVE(server, &nodeId, UA_NODEATTRIBUTESMASK_NONE,
                                        UA_REFERENCETYPESET_NONE,
                                        UA_BROWSEDIRECTION_INVALID);
    if(!node)
        return UA_STATUSCODE_BADNODEIDINVALID;
    node->head.context = nodeContext;
    UA_NODESTORE_RELEASE(server, node);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
                         void *nodeContext) {
    lockServer(server);
    UA_StatusCode retval = setNodeContext(server, nodeId, nodeContext);
    unlockServer(server);
    return retval;
}

static UA_StatusCode
checkSetIsDynamicVariable(UA_Server *server, UA_Session *session,
                          const UA_NodeId *nodeId);

/**********************/
/* Consistency Checks */
/**********************/

#define UA_PARENT_REFERENCES_COUNT 2

static const UA_NodeId parentReferences[UA_PARENT_REFERENCES_COUNT] = {
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}},
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}
};

static void
logAddNode(const UA_Logger *logger, UA_Session *session,
           const UA_NodeId *nodeId, const char *msg) {
    UA_LOG_INFO_SESSION(logger, session, "AddNode (%N): %s", *nodeId, msg);
}

/* Check if the requested parent node exists, has the right node class and is
 * referenced with an allowed (hierarchical) reference type. For "type" nodes,
 * only hasSubType references are allowed. */
static UA_StatusCode
checkParentReference(UA_Server *server, UA_Session *session, const UA_NodeHead *head,
                     const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
    /* Objects do not need a parent (e.g. mandatory/optional modellingrules).
     * Also, there are some variables which do not have parents, e.g.
     * EnumStrings, EnumValues */
    if((head->nodeClass == UA_NODECLASS_OBJECT ||
        head->nodeClass == UA_NODECLASS_VARIABLE) &&
       UA_NodeId_isNull(parentNodeId) && UA_NodeId_isNull(referenceTypeId))
        return UA_STATUSCODE_GOOD;

    /* See if the parent exists */
    const UA_Node *parent = UA_NODESTORE_GET(server, parentNodeId);
    if(!parent) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Parent node %N not found",
                            head->nodeId, *parentNodeId);
        return UA_STATUSCODE_BADPARENTNODEIDINVALID;
    }

    UA_NodeClass parentNodeClass = parent->head.nodeClass;
    UA_NODESTORE_RELEASE(server, parent);

    /* Check the referencetype exists */
    const UA_Node *referenceType = UA_NODESTORE_GET(server, referenceTypeId);
    if(!referenceType) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Reference type %N to the parent not found",
                            head->nodeId, *referenceTypeId);
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    /* Check if the referencetype is a reference type node */
    if(referenceType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Reference type %N to the parent is "
                            "not a ReferenceTypeNode", head->nodeId, *referenceTypeId);
        UA_NODESTORE_RELEASE(server, referenceType);
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    /* Check that the reference type is not abstract */
    UA_Boolean referenceTypeIsAbstract = referenceType->referenceTypeNode.isAbstract;
    UA_NODESTORE_RELEASE(server, referenceType);
    if(referenceTypeIsAbstract == true) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Reference type %N to the parent is abstract",
                            head->nodeId, *referenceTypeId);
        return UA_STATUSCODE_BADREFERENCENOTALLOWED;
    }

    /* Check hassubtype relation for type nodes */
    if(head->nodeClass == UA_NODECLASS_DATATYPE ||
       head->nodeClass == UA_NODECLASS_VARIABLETYPE ||
       head->nodeClass == UA_NODECLASS_OBJECTTYPE ||
       head->nodeClass == UA_NODECLASS_REFERENCETYPE) {
        /* Type needs hassubtype reference to the supertype */
        if(referenceType->referenceTypeNode.referenceTypeIndex !=
           UA_REFERENCETYPEINDEX_HASSUBTYPE) {
            logAddNode(server->config.logging, session, &head->nodeId,
                       "Type nodes need to have a HasSubType reference to the parent");
            return UA_STATUSCODE_BADREFERENCENOTALLOWED;
        }
        /* Supertype needs to be of the same node type  */
        if(parentNodeClass != head->nodeClass) {
            logAddNode(server->config.logging, session, &head->nodeId,
                       "Type nodes needs to be of the same node "
                       "type as their parent");
            return UA_STATUSCODE_BADPARENTNODEIDINVALID;
        }
        return UA_STATUSCODE_GOOD;
    }

    /* Test if the referencetype is hierarchical */
    const UA_NodeId hierarchRefs = UA_NS0ID(HIERARCHICALREFERENCES);
    if(!isNodeInTree_singleRef(server, referenceTypeId, &hierarchRefs,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
        logAddNode(server->config.logging, session, &head->nodeId,
                   "Reference type to the parent is not hierarchical");
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    return UA_STATUSCODE_GOOD;
}

/* Only BaseDataType can have empty values. Generate a default value. */
static UA_StatusCode
setDefaultValue(UA_Server *server, const UA_VariableNode *node) {
    /* Get the DataType */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_DataType *type = UA_Server_findDataType(server, &node->dataType);
    if(!type) {
        /* No description for the DataType found. It is possible that an
         * abstract DataType is used, e.g. UInteger. Browse to see if there is a
         * non-abstract subtype that can be used for the default value.
         *
         * Look up and downwards in the hierarchy. Some data types (e.g.
         * UtcTime) are derived from a non-abstract data type. This is then used
         * for the actual value, Use the first match. */
        UA_ReferenceTypeSet refs = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
        UA_ExpandedNodeId *typeCandidates = NULL;
        size_t typeCandidatesSize = 0;
        res = browseRecursive(server, 1, &node->dataType,
                              UA_BROWSEDIRECTION_BOTH, &refs,
                              UA_NODECLASS_DATATYPE, false,
                              &typeCandidatesSize, &typeCandidates);
        if(res != UA_STATUSCODE_GOOD)
            return res;

        for(size_t i = 0; i < typeCandidatesSize; i++) {
            /* Skip BaseDataType (Variant). This is the root of the DataType
             * hierarchy. Variables of BaseDataType can be empty. */
            if(UA_NodeId_equal(&UA_TYPES[UA_TYPES_VARIANT].typeId,
                               &typeCandidates[i].nodeId))
                continue;

            /* Skip ExtensionObject. Even though we can encode the type it is
             * abstract and nodes should not contain them as value. */
            if(UA_NodeId_equal(&UA_TYPES[UA_TYPES_EXTENSIONOBJECT].typeId,
                               &typeCandidates[i].nodeId))
                continue;

            /* Get the type encoding information */
            type = UA_Server_findDataType(server, &typeCandidates[i].nodeId);
            if(type)
                break;
        }

        UA_Array_delete(typeCandidates, typeCandidatesSize,
                        &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
        if(!type)
            return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Set up the value with the default content */
    UA_Variant val;
    UA_Variant_init(&val);
    if(node->valueRank < 0) {
        /* Set a scalar */
        void *data = UA_new(type);
        if(!data)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        UA_Variant_setScalar(&val, data, type);
    } else {
        /* Set an array
         *
         * https://reference.opcfoundation.org/v104/Core/docs/Part3/5.6.2/#Table13
         * specifies ArrayDimensions as follows: This Attribute specifies the
         * maximum supported length of each dimension. If the maximum is unknown
         * the value shall be 0. The number of elements shall be equal to the
         * value of the ValueRank Attribute. This Attribute shall be null if
         * ValueRank <= 0.
         *
         * The (variant) values themselves cannot have ArrayDimensions with a
         * dimension length of zero. We however consider that empty arrays
         * (null-array or length zero) have implicit array dimensions [0,0,...].
         * With the appropriate number of dimensions. So they always match.
         *
         * We automatically create a null array during the node creation when
         * required for the type-checking..
         *
         * Also see the method 'compatibleValueArrayDimensions' where the
         * compatibility of the ArrayDimensions is checked. */
        UA_Variant_setArray(&val, NULL, 0, type);
    }

    /* Write the value */
    res = writeAttribute(server, &server->adminSession, &node->head.nodeId,
                         UA_ATTRIBUTEID_VALUE, &val, &UA_TYPES[UA_TYPES_VARIANT]);

    /* Clean up */
    UA_Variant_clear(&val);
    return res;
}

static UA_StatusCode
typeCheckVariableNode(UA_Server *server, UA_Session *session,
                      const UA_VariableNode *node,
                      const UA_VariableTypeNode *vt) {
    /* Check the datatype against the vt */
    if(!compatibleDataTypes(server, &node->dataType, &vt->dataType)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The value of is incompatible with "
                   "the datatype of the VariableType");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check valueRank against array dimensions */
    if(!compatibleValueRankArrayDimensions(server, session, node->valueRank,
                                           node->arrayDimensionsSize)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The value rank of is incompatible with its array dimensions");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check valueRank against the vt */
    if(!compatibleValueRanks(node->valueRank, vt->valueRank)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The value rank is incompatible "
                   "with the value rank of the VariableType");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check array dimensions against the vt */
    if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions,
                                  node->arrayDimensionsSize, node->arrayDimensions)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The array dimensions are incompatible with the "
                   "array dimensions of the VariableType");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Typecheck the value. Less strict for NS0 -- we adjust nodes after loading
     * the generated definitions. */
    if(server->bootstrapNS0)
        return UA_STATUSCODE_GOOD;

    /* The value might come from a datasource, so we perform a
     * regular read. */
    UA_DataValue value;
    UA_DataValue_init(&value);
    UA_StatusCode retval = readValueAttribute(server, session, node, &value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* We have a value. Write it back to perform checks and adjustments. */
    const char *reason;
    if(node->valueSourceType == UA_VALUESOURCETYPE_INTERNAL && value.hasValue) {
        if(!compatibleValue(server, session, &node->dataType, node->valueRank,
                            node->arrayDimensionsSize, node->arrayDimensions,
                            &value.value, NULL, &reason)) {
            retval = writeAttribute(server, session, &node->head.nodeId,
                                    UA_ATTRIBUTEID_VALUE, &value.value,
                                    &UA_TYPES[UA_TYPES_VARIANT]);
        }
        UA_DataValue_clear(&value);
        return retval;
    }

    /* Only BaseDataType (Variant) can have empty values */
    if(!value.hasValue &&
       !UA_NodeId_equal(&node->dataType, &UA_TYPES[UA_TYPES_VARIANT].typeId)) {
        /* Warn if that is configured */
        if(server->config.allowEmptyVariables != UA_RULEHANDLING_ACCEPT)
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "AddNode (%N): The value is empty. "
                                 "But this is only allowed for BaseDataType. "
                                 "Create a matching default value.",
                                 node->head.nodeId);

        /* Abort if that is configured */
        if(server->config.allowEmptyVariables == UA_RULEHANDLING_ABORT)
            retval = UA_STATUSCODE_BADTYPEMISMATCH;

        /* Try to generate and write a default value */
        if(server->config.allowEmptyVariables == UA_RULEHANDLING_DEFAULT) {
            retval = setDefaultValue(server, node);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO_SESSION(server->config.logging, session,
                                    "AddNode (%N): Could not create a default value "
                                    "with StatusCode %s", node->head.nodeId,
                                    UA_StatusCode_name(retval));
            }
        }
        return retval;
    }

    /* Type-check the value */
    UA_Boolean compatible =
        compatibleValue(server, session, &node->dataType,
            node->valueRank, node->arrayDimensionsSize,
            node->arrayDimensions, &value.value, NULL, &reason);
    if(!compatible) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): The VariableNode value has "
                            "failed the type check with reason %s. ",
                            node->head.nodeId, reason);
        retval = UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_DataValue_clear(&value);
    return retval;
}

/********************/
/* Instantiate Node */
/********************/

static const UA_NodeId baseDataVariableType =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEDATAVARIABLETYPE}};
static const UA_NodeId baseObjectType =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEOBJECTTYPE}};
static const UA_NodeId hasTypeDefinition =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASTYPEDEFINITION}};

/* Use attributes from the variable type wherever required. Reload the node if
 * changes were made. */
static UA_StatusCode
useVariableTypeAttributes(UA_Server *server, UA_Session *session,
                          const UA_VariableNode *node,
                          const UA_VariableTypeNode *vt) {
    /* If no value is set, see if the vt provides one and copy it. This needs to
     * be done before copying the datatype from the vt, as setting the datatype
     * triggers a typecheck. */
    UA_DataValue origDv;
    UA_DataValue_init(&origDv);
    UA_StatusCode retval = readValueAttribute(server, session, node, &origDv);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(origDv.hasValue && origDv.value.type) {
        /* A value is present */
        UA_DataValue_clear(&origDv);
    } else {
        UA_DataValue_clear(&origDv);
        UA_DataValue v;
        UA_DataValue_init(&v);
        retval = readValueAttribute(server, session, (const UA_VariableNode*)vt, &v);
        if(retval == UA_STATUSCODE_GOOD && v.hasValue) {
            retval = writeAttribute(server, session, &node->head.nodeId,
                                    UA_ATTRIBUTEID_VALUE, &v.value,
                                    &UA_TYPES[UA_TYPES_VARIANT]);
        }
        UA_DataValue_clear(&v);

        if(retval != UA_STATUSCODE_GOOD) {
            logAddNode(server->config.logging, session, &node->head.nodeId,
                       "The default content of the VariableType could "
                       "not be used. This may happen if the VariableNode "
                       "makes additional restrictions.");
            retval = UA_STATUSCODE_GOOD;
        }
    }

    /* If no datatype is given, use the datatype of the vt */
    if(UA_NodeId_isNull(&node->dataType)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "No datatype given; Copy the datatype attribute "
                   "from the TypeDefinition");
        retval = writeAttribute(server, session, &node->head.nodeId,
                                UA_ATTRIBUTEID_DATATYPE, &vt->dataType,
                                &UA_TYPES[UA_TYPES_NODEID]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    /* Use the ArrayDimensions of the vt */
    if(node->arrayDimensionsSize == 0 && vt->arrayDimensionsSize > 0) {
        UA_Variant v;
        UA_Variant_init(&v);
        UA_Variant_setArray(&v, vt->arrayDimensions, vt->arrayDimensionsSize,
                            &UA_TYPES[UA_TYPES_UINT32]);
        retval = writeAttribute(server, session, &node->head.nodeId,
                                UA_ATTRIBUTEID_ARRAYDIMENSIONS, &v,
                                &UA_TYPES[UA_TYPES_VARIANT]);
    }

    return retval;
}

struct findChildContext {
    UA_Server *server;
    UA_QualifiedName browseName;
    UA_UInt32 browseNameHash;
    UA_NodeClass nodeClassMask;
    UA_NodeId *outInstanceNodeId;
};

static void *
findChildCallback(void *context, UA_ReferenceTarget *t) {
    struct findChildContext *ctx = (struct findChildContext*)context;

    /* No ExpandedNodeId pointing to another server */
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;

    /* Compare the hash (fast) */
    if(t->targetNameHash != ctx->browseNameHash)
        return NULL;

    /* Get the node to compare the full attributes */
    const UA_Node *refTarget =
        UA_NODESTORE_GETFROMREF_SELECTIVE(ctx->server, t->targetId,
                                          UA_NODEATTRIBUTESMASK_BROWSENAME,
                                          UA_REFERENCETYPESET_NONE,
                                          UA_BROWSEDIRECTION_INVALID);
    if(!refTarget)
        return NULL;

    /* Compare NodeClass and BrowseName */
    if(!(refTarget->head.nodeClass & ctx->nodeClassMask) ||
       !UA_QualifiedName_equal(&ctx->browseName, &refTarget->head.browseName)) {
        UA_NODESTORE_RELEASE(ctx->server, refTarget);
        return NULL;
    }

    UA_NODESTORE_RELEASE(ctx->server, refTarget);

    /* Copy the child NodeId and return a sentinel value */
    UA_NodeId origId = UA_NodePointer_toNodeId(t->targetId);
    UA_StatusCode res = UA_NodeId_copy(&origId, ctx->outInstanceNodeId);
    return (res == UA_STATUSCODE_GOOD) ? (void*)0x01 : (void*)0x02;
}

UA_StatusCode
findChildByBrowsename(UA_Server *server, UA_Session *session,
                      const UA_NodeId parentId, UA_NodeClass nodeClassMask,
                      const UA_Byte refType, const UA_NodeId refTypeId,
                      const UA_QualifiedName *browseName,
                      UA_NodeId *outChildNodeId) {
    /* Begin with HasComponent references only. This is the most common case as
     * a "fast path". If this fails also look for subtypes of HasComponent. */
    UA_Boolean subTypes = false;
    UA_ReferenceTypeSet refTypes = UA_REFTYPESET(refType);

    /* Setup the context */
    struct findChildContext ctx;
    ctx.server = server;
    ctx.browseName = *browseName;
    ctx.browseNameHash = UA_QualifiedName_hash(browseName);
    ctx.nodeClassMask = nodeClassMask;
    ctx.outInstanceNodeId = outChildNodeId;

    /* Get the parent node */
    void *found = NULL;
    const UA_Node *parent;
 get_parent:
    parent = UA_NODESTORE_GET_SELECTIVE(server, &parentId,
                                        UA_NODEATTRIBUTESMASK_NONE,
                                        refTypes, UA_BROWSEDIRECTION_FORWARD);
    if(!parent)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* Loop over the references to find a match */
    for(size_t i = 0; i < parent->head.referencesSize; i++) {
        UA_NodeReferenceKind *rk = &parent->head.references[i];
        if(rk->isInverse)
            continue;
        if(!UA_ReferenceTypeSet_contains(&refTypes, rk->referenceTypeIndex))
            continue;
        found = UA_NodeReferenceKind_iterate(rk, findChildCallback, &ctx);
        if(found)
            break;
    }

    UA_NODESTORE_RELEASE(server, parent);

    /* Also consider subtypes of for references*/
    if(!found && !subTypes) {
        UA_StatusCode res =
            referenceTypeIndices(server, &refTypeId, &refTypes, true);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        subTypes = true;
        goto get_parent;
    }

    /* Error */
    if(found == (void *)0x02)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Done */
    return (found) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOTFOUND;
}

static const UA_ExpandedNodeId mandatoryId =
    {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_MODELLINGRULE_MANDATORY}}, {0, NULL}, 0};

static UA_Boolean
isMandatoryChild(UA_Server *server, UA_Session *session,
                 const UA_NodeId *childNodeId) {
    /* Get the child */
    const UA_Node *child = UA_NODESTORE_GET(server, childNodeId);
    if(!child)
        return false;

    /* Look for the reference making the child mandatory */
    UA_Boolean found = false;
    for(size_t i = 0; i < child->head.referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &child->head.references[i];
        if(rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASMODELLINGRULE)
            continue;
        if(rk->isInverse)
            continue;

        if(UA_NodeReferenceKind_findTarget(rk, &mandatoryId)) {
            found = true;
            break;
        }
    }

    UA_NODESTORE_RELEASE(server, child);
    return found;
}

static UA_StatusCode
copyAllChildren(UA_Server *server, UA_Session *session,
                const UA_NodeId *source, const UA_NodeId *destination);

static void
Operation_addReference(UA_Server *server, UA_Session *session, void *context,
                       const UA_AddReferencesItem *item, UA_StatusCode *retval);

UA_StatusCode
addRefWithSession(UA_Server *server, UA_Session *session, const UA_NodeId *sourceId,
                  const UA_NodeId *referenceTypeId, const UA_NodeId *targetId,
                  UA_Boolean forward) {
    UA_AddReferencesItem ref_item;
    UA_AddReferencesItem_init(&ref_item);
    ref_item.sourceNodeId = *sourceId;
    ref_item.referenceTypeId = *referenceTypeId;
    ref_item.isForward = forward;
    ref_item.targetNodeId.nodeId = *targetId;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    Operation_addReference(server, session, NULL, &ref_item, &retval);
    return retval;
}

UA_StatusCode
addRef(UA_Server *server, const UA_NodeId sourceId,
       const UA_NodeId referenceTypeId, const UA_NodeId targetId,
       UA_Boolean forward) {
    return addRefWithSession(server, &server->adminSession, &sourceId,
                             &referenceTypeId, &targetId, forward);
}

static UA_StatusCode
addInterfaceChildren(UA_Server *server, UA_Session *session,
                     const UA_NodeId *nodeId) {
    /* Get the hierarchy of the type and all its supertypes */
    UA_NodeId *hierarchy = NULL;
    size_t hierarchySize = 0;
    UA_StatusCode retval = getAllInterfaces(server, nodeId, &hierarchy, &hierarchySize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Copy members of the type and supertypes (and instantiate them) */
    for(size_t i = 0; i < hierarchySize; ++i) {
        retval = copyAllChildren(server, session, &hierarchy[i], nodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
            return retval;
        }
    }

    for(size_t i = 0; i < hierarchySize; ++i) {
        UA_NodeId refId = UA_NS0ID(HASINTERFACE);
        retval = addRef(server, *nodeId, refId, hierarchy[i], true);

        /* Don't add the original HasInterface reference to ObjectType sub nodes */
        if(retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
            retval = UA_STATUSCODE_GOOD;
        } else if(retval != UA_STATUSCODE_GOOD) {
            break;
        }
    }

    UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
    return retval;
}

static UA_StatusCode
copyObjectVariableChild(UA_Server *server, UA_Session *session,
                        const UA_NodeId *destinationNodeId,
                        const UA_ReferenceDescription *rd) {
    /* Make a copy of the node */
    UA_Node *node;
    UA_StatusCode res = UA_NODESTORE_GETCOPY(server, &rd->nodeId.nodeId, &node);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Remove the context of the copied node */
    node->head.context = NULL;
    node->head.constructed = false;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    node->head.monitoredItems = NULL;
#endif

    /* The value source callbacks are copied by default. But we don't want
     * to keep it here. */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
       node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) {
        if(node->variableNode.valueSourceType == UA_VALUESOURCETYPE_INTERNAL ||
           node->variableNode.valueSourceType == UA_VALUESOURCETYPE_EXTERNAL) {
            memset(&node->variableNode.valueSource.internal.notifications, 0,
                   sizeof(UA_ValueSourceNotifications));
        } else {
            memset(&node->variableNode.valueSource.callback, 0,
                   sizeof(UA_CallbackValueSource));

        }
        node->variableNode.valueSourceType = UA_VALUESOURCETYPE_INTERNAL;
    }

    /* Reset the NodeId (random numeric id will be assigned in the nodestore) */
    UA_NodeId_clear(&node->head.nodeId);
    node->head.nodeId.namespaceIndex = destinationNodeId->namespaceIndex;
    if(server->config.nodeLifecycle &&
       server->config.nodeLifecycle->generateChildNodeId) {
        res = server->config.nodeLifecycle->
            generateChildNodeId(server, &session->sessionId, session->context,
                                &rd->nodeId.nodeId, destinationNodeId,
                                &rd->referenceTypeId, &node->head.nodeId);
        if(res != UA_STATUSCODE_GOOD) {
            UA_NODESTORE_DELETE(server, node);
            return res;
        }
    }

    /* Remove references, they are re-created from scratch in
     * addnode_finish. For now we keep all the modelling rule references and
     * delete all others. */

    /* TODO: Be more clever in removing references that are re-added during
     * addnode_finish. That way, we can call addnode_finish also on children
     * that were manually added by the user during addnode_begin and
     * addnode_finish. */
    const UA_NodeId nodeId_typesFolder = UA_NS0ID(TYPESFOLDER);
    const UA_ReferenceTypeSet reftypes_aggregates =
        UA_REFTYPESET(UA_REFERENCETYPEINDEX_AGGREGATES);
    UA_ReferenceTypeSet reftypes_skipped =
        UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE);
    if(server->config.modellingRulesOnInstances ||
       isNodeInTree(server, destinationNodeId,
                    &nodeId_typesFolder, &reftypes_aggregates)) {
        /* hasModellingRule-reference is required (configured or node in an
         * instance declaration) */
        UA_ReferenceTypeSet_add(&reftypes_skipped,
                                UA_REFERENCETYPEINDEX_HASMODELLINGRULE);
    }
    UA_Node_deleteReferencesSubset(node, &reftypes_skipped);

    /* Add the node to the nodestore */
    UA_NodeId newNodeId = UA_NODEID_NULL;
    res = UA_NODESTORE_INSERT(server, node, &newNodeId);
    /* node = NULL; The pointer is no longer valid */
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Add the node references */
    res = addNode_addRefs(server, session, &newNodeId, destinationNodeId,
                          &rd->referenceTypeId, &rd->typeDefinition.nodeId);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    if(rd->nodeClass == UA_NODECLASS_VARIABLE) {
        res = checkSetIsDynamicVariable(server, session, &newNodeId);
        if(res != UA_STATUSCODE_GOOD)
            goto errout;
    }

    /* For the new child, recursively copy the members of the original. No
     * typechecking is performed here. Assuming that the original is
     * consistent. */
    res = copyAllChildren(server, session, &rd->nodeId.nodeId, &newNodeId);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Check if its a dynamic variable, add all type and/or interface
     * children and call the constructor */
    res = addNode_finish(server, session, &newNodeId);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

 errout:
    /* Clean up */
    if(res != UA_STATUSCODE_GOOD)
        deleteNode(server, newNodeId, true);
    UA_NodeId_clear(&newNodeId);
    return res;
}

static UA_StatusCode
copyChild(UA_Server *server, UA_Session *session,
          const UA_NodeId *destinationNodeId,
          const UA_ReferenceDescription *rd) {
    UA_assert(session);
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Is there an existing child with the browsename? */
    UA_NodeId existingChild = UA_NODEID_NULL;
    UA_NodeClass childNodeClass = (UA_NodeClass)
        (UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD);
    UA_StatusCode retval = findChildByBrowsename(server, session,
                                                 *destinationNodeId, childNodeClass,
                                                 UA_REFERENCETYPEINDEX_AGGREGATES,
                                                 UA_NS0ID(AGGREGATES), &rd->browseName,
                                                 &existingChild);

    /* Existing child with that browseName. Deep-copy missing members. */
    if(retval == UA_STATUSCODE_GOOD) {
        if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
           rd->nodeClass == UA_NODECLASS_OBJECT)
            retval = copyAllChildren(server, session, &rd->nodeId.nodeId, &existingChild);
        UA_NodeId_clear(&existingChild);
        return retval;
    }

    /* An error occurred (besides not finding an existing child) */
    if(retval != UA_STATUSCODE_BADNOTFOUND)
        return retval;

    /* Is the child mandatory? If not, ask callback whether child should be instantiated.
     * If not, skip. */
    if(!isMandatoryChild(server, session, &rd->nodeId.nodeId)) {
        if(!server->config.nodeLifecycle ||
           !server->config.nodeLifecycle->createOptionalChild)
            return UA_STATUSCODE_GOOD;
        UA_Boolean createChild = server->config.nodeLifecycle->
            createOptionalChild(server, &session->sessionId, session->context,
                                &rd->nodeId.nodeId, destinationNodeId, &rd->referenceTypeId);
        if(!createChild)
            return UA_STATUSCODE_GOOD;
    }

    /* Child is a method -> create a reference */
    if(rd->nodeClass == UA_NODECLASS_METHOD) {
        UA_AddReferencesItem newItem;
        UA_AddReferencesItem_init(&newItem);
        newItem.sourceNodeId = *destinationNodeId;
        newItem.referenceTypeId = rd->referenceTypeId;
        newItem.isForward = true;
        newItem.targetNodeId = rd->nodeId;
        newItem.targetNodeClass = UA_NODECLASS_METHOD;
        Operation_addReference(server, session, NULL, &newItem, &retval);
        return retval;
    }

    /* Child is a variable or object */
    if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
       rd->nodeClass == UA_NODECLASS_OBJECT) {
        retval = copyObjectVariableChild(server, session, destinationNodeId, rd);
    }

    return retval;
}

/* Copy any children of Node sourceNodeId to another node destinationNodeId. */
static UA_StatusCode
copyAllChildren(UA_Server *server, UA_Session *session,
                const UA_NodeId *source, const UA_NodeId *destination) {
    /* Browse to get all children of the source */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *source;
    bd.referenceTypeId = UA_NS0ID(AGGREGATES);
    bd.includeSubtypes = true;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
    bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
    bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS |
        UA_BROWSERESULTMASK_BROWSENAME | UA_BROWSERESULTMASK_TYPEDEFINITION;

    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, session, &maxrefs, &bd, &br);
    if(br.statusCode != UA_STATUSCODE_GOOD)
        return br.statusCode;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < br.referencesSize; ++i) {
        UA_ReferenceDescription *rd = &br.references[i];
        retval = copyChild(server, session, destination, rd);
        if(retval != UA_STATUSCODE_GOOD)
            break;
    }

    UA_BrowseResult_clear(&br);
    return retval;
}

static UA_StatusCode
addTypeChildren(UA_Server *server, UA_Session *session,
                const UA_NodeId *nodeId, const UA_NodeId *typeId) {
    /* Get the hierarchy of the type and all its supertypes */
    UA_NodeId *hierarchy = NULL;
    size_t hierarchySize = 0;
    UA_StatusCode retval =
        getTypeAndInterfaceHierarchy(server, typeId, true,
                                     &hierarchy, &hierarchySize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Copy members of the type and supertypes (and instantiate them) */
    for(size_t i = 0; i < hierarchySize; ++i) {
        retval = copyAllChildren(server, session, &hierarchy[i], nodeId);
        if(retval != UA_STATUSCODE_GOOD)
            break;
    }

    UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
    return retval;
}

/************/
/* Add Node */
/************/

static const UA_NodeId hasSubtype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};

UA_StatusCode
addNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
                const UA_NodeId *typeDefinitionId) {
    /* Get the node */
    const UA_Node *type = NULL;
    const UA_Node *node = UA_NODESTORE_GET(server, nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* Use the typeDefinition as parent for type-nodes */
    const UA_NodeHead *head = &node->head;
    if(head->nodeClass == UA_NODECLASS_VARIABLETYPE ||
       head->nodeClass == UA_NODECLASS_OBJECTTYPE ||
       head->nodeClass == UA_NODECLASS_REFERENCETYPE ||
       head->nodeClass == UA_NODECLASS_DATATYPE) {
        if(UA_NodeId_equal(referenceTypeId, &UA_NODEID_NULL))
            referenceTypeId = &hasSubtype;
        const UA_Node *parentNode = UA_NODESTORE_GET(server, parentNodeId);
        if(parentNode) {
            if(parentNode->head.nodeClass == head->nodeClass)
                typeDefinitionId = parentNodeId;
            UA_NODESTORE_RELEASE(server, parentNode);
        }
    }

    UA_StatusCode retval;
    /* Make sure newly created node does not have itself as parent */
    if(UA_NodeId_equal(nodeId, parentNodeId)) {
        logAddNode(server->config.logging, session, nodeId,
                   "A node cannot have itself as parent");
        retval = UA_STATUSCODE_BADINVALIDARGUMENT;
        goto cleanup;
    }


    /* Check parent reference. Objects may have no parent. */
    retval = checkParentReference(server, session, head, parentNodeId, referenceTypeId);
    if(retval != UA_STATUSCODE_GOOD) {
        logAddNode(server->config.logging, session, nodeId,
                   "The parent reference is invalid");
        goto cleanup;
    }

    /* Replace empty typeDefinition with the most permissive default */
    if((head->nodeClass == UA_NODECLASS_VARIABLE ||
        head->nodeClass == UA_NODECLASS_OBJECT) &&
       UA_NodeId_isNull(typeDefinitionId)) {
        logAddNode(server->config.logging, session, nodeId,
                   "No TypeDefinition. Use the default "
                   "TypeDefinition for the Variable/Object");
        if(head->nodeClass == UA_NODECLASS_VARIABLE)
            typeDefinitionId = &baseDataVariableType;
        else
            typeDefinitionId = &baseObjectType;
    }

    /* Get the node type. There must be a typedefinition for variables, objects
     * and type-nodes. See the above checks. */
    if(!UA_NodeId_isNull(typeDefinitionId)) {
        /* Get the type node */
        type = UA_NODESTORE_GET(server, typeDefinitionId);
        if(!type) {
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%N): Node type %N not found ",
                                *nodeId, *typeDefinitionId);
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }

        UA_Boolean typeOk = false;
        const UA_NodeHead *typeHead = &type->head;
        switch(head->nodeClass) {
            case UA_NODECLASS_DATATYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_DATATYPE;
                break;
            case UA_NODECLASS_METHOD:
                typeOk = typeHead->nodeClass == UA_NODECLASS_METHOD;
                break;
            case UA_NODECLASS_OBJECT:
            case UA_NODECLASS_OBJECTTYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_OBJECTTYPE;
                break;
            case UA_NODECLASS_REFERENCETYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_REFERENCETYPE;
                break;
            case UA_NODECLASS_VARIABLE:
            case UA_NODECLASS_VARIABLETYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_VARIABLETYPE;
                break;
            case UA_NODECLASS_VIEW:
                typeOk = typeHead->nodeClass == UA_NODECLASS_VIEW;
                break;
            default:
                typeOk = false;
        }
        if(!typeOk) {
            logAddNode(server->config.logging, session, nodeId,
                       "Type does not match the NodeClass");
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }

        /* See if the type has the correct node class. For type-nodes, we know
         * that type has the same nodeClass from checkParentReference. */
        if(head->nodeClass == UA_NODECLASS_VARIABLE &&
           type->variableTypeNode.isAbstract) {
            /* Get subtypes of the parent reference types */
            UA_ReferenceTypeSet refTypes1, refTypes2;
            retval |= referenceTypeIndices(server, &parentReferences[0], &refTypes1, true);
            retval |= referenceTypeIndices(server, &parentReferences[1], &refTypes2, true);
            UA_ReferenceTypeSet refTypes = UA_ReferenceTypeSet_union(refTypes1, refTypes2);
            if(retval != UA_STATUSCODE_GOOD)
                goto cleanup;

            /* Abstract variable is allowed if parent is a children of a
             * base data variable. An abstract variable may be part of an
             * object type which again is below BaseObjectType.
             * When the parent is not set (e.g. generated namespace code where
             * the parent reference is non-hierarchical), we skip the check. */
            const UA_NodeId variableTypes = UA_NS0ID(BASEDATAVARIABLETYPE);
            const UA_NodeId objectTypes = UA_NS0ID(BASEOBJECTTYPE);
            if(!UA_NodeId_isNull(parentNodeId) &&
               !isNodeInTree(server, parentNodeId, &variableTypes, &refTypes) &&
               !isNodeInTree(server, parentNodeId, &objectTypes, &refTypes)) {
                logAddNode(server->config.logging, session, nodeId,
                           "Type of variable node must be a "
                           "VariableType and cannot be abstract");
                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                goto cleanup;
            }
        }

        if(head->nodeClass == UA_NODECLASS_OBJECT &&
           type->objectTypeNode.isAbstract) {
            /* Get subtypes of the parent reference types */
            UA_ReferenceTypeSet refTypes1, refTypes2;
            retval |= referenceTypeIndices(server, &parentReferences[0], &refTypes1, true);
            retval |= referenceTypeIndices(server, &parentReferences[1], &refTypes2, true);
            UA_ReferenceTypeSet refTypes = UA_ReferenceTypeSet_union(refTypes1, refTypes2);
            if(retval != UA_STATUSCODE_GOOD)
                goto cleanup;


            /* Object node created of an abstract ObjectType. Only allowed if
             * within BaseObjectType folder, or if it's an event (subType of
             * BaseEventType), or if the parent is not set (e.g. generated
             * namespace code where the parent reference is
             * non-hierarchical). */
            const UA_NodeId objectTypes = UA_NS0ID(BASEOBJECTTYPE);
            UA_Boolean isInBaseObjectType =
                isNodeInTree(server, parentNodeId, &objectTypes, &refTypes);

            if(!isInBaseObjectType && !UA_NodeId_isNull(parentNodeId)) {
                logAddNode(server->config.logging, session, nodeId,
                           "Type of ObjectNode must be ObjectType and not be abstract");
                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                goto cleanup;
            }
        }
    }

    /* Add reference to the parent */
    if(!UA_NodeId_isNull(parentNodeId)) {
        if(UA_NodeId_isNull(referenceTypeId)) {
            logAddNode(server->config.logging, session, nodeId,
                       "Reference to parent cannot be null");
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }

        retval = addRefWithSession(server, session, &head->nodeId, referenceTypeId,
                                   parentNodeId, false);
        if(retval != UA_STATUSCODE_GOOD) {
            logAddNode(server->config.logging, session, nodeId,
                       "Adding reference to parent failed");
            goto cleanup;
        }
    }

    /* Add a hasTypeDefinition reference */
    if(head->nodeClass == UA_NODECLASS_VARIABLE ||
       head->nodeClass == UA_NODECLASS_OBJECT) {
        UA_assert(type != NULL); /* see above */
        retval = addRefWithSession(server, session, &head->nodeId, &hasTypeDefinition,
                                   &type->head.nodeId, true);
        if(retval != UA_STATUSCODE_GOOD) {
            logAddNode(server->config.logging, session, nodeId,
                       "Adding a reference to the type definition failed");
        }
    }

 cleanup:
    UA_NODESTORE_RELEASE(server, node);
    if(type)
        UA_NODESTORE_RELEASE(server, type);
    return retval;
}

/* Create the node and add it to the nodestore. But don't typecheck and add
 * references so far */
UA_StatusCode
addNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
            const UA_AddNodesItem *item, UA_NodeId *outNewNodeId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Do not check access for server */
    if(session != &server->adminSession && server->config.accessControl.allowAddNode) {
        if(!server->config.accessControl.
           allowAddNode(server, &server->config.accessControl,
                        &session->sessionId, session->context, item)) {
            return UA_STATUSCODE_BADUSERACCESSDENIED;
        }
    }

    /* Check the NamespaceIndex */
    if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Namespace invalid",
                            item->requestedNewNodeId.nodeId);
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    if(item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED &&
       item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Node attributes invalid",
                            item->requestedNewNodeId.nodeId);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create a Node */
    UA_Node *node = UA_NODESTORE_NEW(server, item->nodeClass);
    if(!node) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode: Could not create a node "
                            "in the nodestore");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_NodeId tmpOutId = UA_NODEID_NULL;

    /* Fill the node attributes. If an error occurs, the memory in the node is
     * cleaned up inside UA_NODESTORE_DELETE. */
    node->head.context = nodeContext;
    UA_StatusCode retval =
        UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->head.nodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto create_error;

    retval = UA_QualifiedName_copy(&item->browseName, &node->head.browseName);
    if(retval != UA_STATUSCODE_GOOD)
        goto create_error;

    retval = UA_Node_setAttributes(node, item->nodeAttributes.content.decoded.data,
                                   item->nodeAttributes.content.decoded.type);
    if(retval != UA_STATUSCODE_GOOD)
        goto create_error;

    /* Create a current source timestamp for values that don't have any */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
        UA_VariableNode *vn = &node->variableNode;
        if(vn->valueSourceType == UA_VALUESOURCETYPE_INTERNAL &&
           !vn->valueSource.internal.value.hasSourceTimestamp) {
            UA_EventLoop *el = server->config.eventLoop;
            vn->valueSource.internal.value.sourceTimestamp = el->dateTime_now(el);
            vn->valueSource.internal.value.hasSourceTimestamp = true;
        }
    }

    /* Add the node to the Nodestore */
    if(!outNewNodeId)
        outNewNodeId = &tmpOutId;
    retval = UA_NODESTORE_INSERT(server, node, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Could not add the new node "
                            "to the Nodestore with status %s",
                            item->requestedNewNodeId.nodeId,
                            UA_StatusCode_name(retval));
        return retval;
    }

    if(outNewNodeId == &tmpOutId)
        UA_NodeId_clear(&tmpOutId);

    return UA_STATUSCODE_GOOD;

create_error:
    UA_LOG_INFO_SESSION(server->config.logging, session,
                        "AddNode (%N): Could not create node "
                        "with status %s", node->head.nodeId,
                        UA_StatusCode_name(retval));
    UA_NODESTORE_DELETE(server, node);
    return retval;
}

static UA_StatusCode
findDefaultInstanceBrowseNameNode(UA_Server *server, UA_NodeId startingNode,
                                  UA_NodeId *foundId) {
    UA_NodeId_init(foundId);
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = UA_NS0ID(HASPROPERTY);
    rpe.targetName = UA_QUALIFIEDNAME(0, "DefaultInstanceBrowseName");
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = startingNode;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    UA_StatusCode retval = bpr.statusCode;
    if(retval == UA_STATUSCODE_GOOD && bpr.targetsSize > 0)
        retval = UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, foundId);
    UA_BrowsePathResult_clear(&bpr);
    return retval;
}

/* Check if we got a valid browse name for the new node. For object nodes the
 * BrowseName may only be null if the parent type has a
 * 'DefaultInstanceBrowseName' property. */
static UA_StatusCode
checkSetBrowseName(UA_Server *server, UA_Session *session, UA_AddNodesItem *item) {
    /* If the object node already has a browse name we are done here. */
    if(!UA_QualifiedName_isNull(&item->browseName))
        return UA_STATUSCODE_GOOD;

    /* Nodes other than Objects must have a BrowseName */
    if(item->nodeClass != UA_NODECLASS_OBJECT)
        return UA_STATUSCODE_BADBROWSENAMEINVALID;

    /* At this point we have an object with an empty browse name. Check the type
     * node if it has a DefaultInstanceBrowseName property. */
    UA_NodeId defaultBrowseNameNode;
    UA_StatusCode retval =
        findDefaultInstanceBrowseNameNode(server, item->typeDefinition.nodeId,
                                          &defaultBrowseNameNode);
    if(retval != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADBROWSENAMEINVALID;

    UA_Variant defaultBrowseName;
    retval = readWithReadValue(server, &defaultBrowseNameNode,
                               UA_ATTRIBUTEID_VALUE, &defaultBrowseName);
    UA_NodeId_clear(&defaultBrowseNameNode);
    if(retval != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADBROWSENAMEINVALID;

    if(UA_Variant_hasScalarType(&defaultBrowseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME])) {
        item->browseName = *(UA_QualifiedName*)defaultBrowseName.data;
        UA_QualifiedName_init((UA_QualifiedName*)defaultBrowseName.data);
    } else {
        retval = UA_STATUSCODE_BADBROWSENAMEINVALID;
    }

    UA_Variant_clear(&defaultBrowseName);
    return retval;
}

/* Prepare the node, then add it to the nodestore */
static UA_StatusCode
Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
                        const UA_AddNodesItem *item, const UA_NodeId *parentNodeId,
                        const UA_NodeId *referenceTypeId, UA_NodeId *outNewNodeId) {
    /* Create a temporary NodeId if none is returned */
    UA_NodeId newId;
    if(!outNewNodeId) {
        UA_NodeId_init(&newId);
        outNewNodeId = &newId;
    }

    /* Set the BrowsenName before adding to the Nodestore. The BrowseName is
     * immutable afterwards. */
    UA_Boolean noBrowseName = UA_QualifiedName_isNull(&item->browseName);
    UA_StatusCode retval =
        checkSetBrowseName(server, session, (UA_AddNodesItem*)(uintptr_t)item);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Create the node and add it to the nodestore */
    retval = addNode_raw(server, session, nodeContext, item, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Typecheck and add references to parent and type definition */
    retval = addNode_addRefs(server, session, outNewNodeId, parentNodeId,
                             referenceTypeId, &item->typeDefinition.nodeId);
    if(retval != UA_STATUSCODE_GOOD)
        deleteNode(server, *outNewNodeId, true);

    if(outNewNodeId == &newId)
        UA_NodeId_clear(&newId);

 cleanup:
    if(noBrowseName)
        UA_QualifiedName_clear((UA_QualifiedName*)(uintptr_t)&item->browseName);
    return retval;
}

/* Construct children first */
static UA_StatusCode
recursiveCallConstructors(UA_Server *server, UA_Session *session,
                          const UA_NodeId *nodeId, const UA_Node *type) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Browse the children */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *nodeId;
    bd.referenceTypeId = UA_NS0ID(AGGREGATES);
    bd.includeSubtypes = true;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;

    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, session, &maxrefs, &bd, &br);
    if(br.statusCode != UA_STATUSCODE_GOOD)
        return br.statusCode;

    /* Call the constructor for every unconstructed child node */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < br.referencesSize; ++i) {
        UA_ReferenceDescription *rd = &br.references[i];
        if(!UA_ExpandedNodeId_isLocal(&rd->nodeId))
            continue;
        const UA_Node *target = UA_NODESTORE_GET(server, &rd->nodeId.nodeId);
        if(!target)
            continue;
        if(target->head.constructed) {
            UA_NODESTORE_RELEASE(server, target);
            continue;
        }

        /* TODO: Do we need all attributes and references here?  */
        const UA_Node *targetType = NULL;
        if(target->head.nodeClass == UA_NODECLASS_VARIABLE ||
           target->head.nodeClass == UA_NODECLASS_OBJECT) {
            targetType = getNodeType(server, &target->head, ~(UA_UInt32)0,
                                     UA_REFERENCETYPESET_ALL,
                                     UA_BROWSEDIRECTION_BOTH);
            if(!targetType) {
                UA_NODESTORE_RELEASE(server, target);
                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                break;
            }
        }

        UA_NODESTORE_RELEASE(server, target);
        retval = recursiveCallConstructors(server, session, &rd->nodeId.nodeId, targetType);

        if(targetType)
            UA_NODESTORE_RELEASE(server, targetType);
        if(retval != UA_STATUSCODE_GOOD)
            break;
    }

    UA_BrowseResult_clear(&br);

    /* If a child could not be constructed or the node is already constructed */
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Get the node context */
    const UA_Node *node = UA_NODESTORE_GET(server, nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    void *context = node->head.context;
    UA_NODESTORE_RELEASE(server, node);

    /* Call the global constructor */
    if(server->config.nodeLifecycle &&
       server->config.nodeLifecycle->constructor) {
        retval = server->config.nodeLifecycle->
            constructor(server, &session->sessionId,
                        session->context, nodeId, &context);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    /* Call the local (per-type) constructor */
    const UA_NodeTypeLifecycle *lifecycle = NULL;
    if(type && node->head.nodeClass == UA_NODECLASS_OBJECT)
        lifecycle = &type->objectTypeNode.lifecycle;
    else if(type && node->head.nodeClass == UA_NODECLASS_VARIABLE)
        lifecycle = &type->variableTypeNode.lifecycle;
    if(lifecycle && lifecycle->constructor) {
        retval = lifecycle->constructor(server, &session->sessionId,
                                        session->context, &type->head.nodeId,
                                        type->head.context, nodeId, &context);
        if(retval != UA_STATUSCODE_GOOD)
            goto global_destructor;
    }

    /* Set the context *and* mark the node as constructed */
    retval = editNode(server, &server->adminSession, nodeId,
                      0, UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                      (UA_EditNodeCallback)setConstructedNodeContext, context);
    if(retval != UA_STATUSCODE_GOOD)
        goto local_destructor;

    /* All good, return */
    return retval;

    /* Fail. Call the destructors. */
  local_destructor:
    if(lifecycle && lifecycle->destructor) {
        lifecycle->destructor(server, &session->sessionId, session->context,
                              &type->head.nodeId, type->head.context, nodeId, &context);
    }

  global_destructor:
    if(server->config.nodeLifecycle && server->config.nodeLifecycle->destructor) {
        server->config.nodeLifecycle->destructor(server, &session->sessionId,
                                                 session->context, nodeId, context);
    }
    return retval;
}

/* Add new ReferenceType to the subtypes bitfield */
static UA_StatusCode
addReferenceTypeSubtype(UA_Server *server, UA_Session *session,
                        UA_Node *node, void *context) {
    node->referenceTypeNode.subTypes =
        UA_ReferenceTypeSet_union(node->referenceTypeNode.subTypes,
                                  *(UA_ReferenceTypeSet*)context);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setReferenceTypeSubtypes(UA_Server *server, const UA_ReferenceTypeNode *node) {
    /* Get the ReferenceTypes upwards in the hierarchy */
    size_t parentsSize = 0;
    UA_ExpandedNodeId *parents = NULL;
    UA_ReferenceTypeSet reftypes_subtype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
    UA_StatusCode res =
        browseRecursive(server, 1, &node->head.nodeId, UA_BROWSEDIRECTION_INVERSE,
                        &reftypes_subtype, UA_NODECLASS_UNSPECIFIED,
                        false, &parentsSize, &parents);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Add the ReferenceTypeIndex of this node */
    const UA_ReferenceTypeSet *newRefSet = &node->subTypes;
    for(size_t i = 0; i < parentsSize; i++) {
        editNode(server, &server->adminSession, &parents[i].nodeId,
                 0, UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                 addReferenceTypeSubtype, (void*)(uintptr_t)newRefSet);
    }

    UA_Array_delete(parents, parentsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setVariableNodeDynamic(UA_Server *server, const UA_NodeId *nodeId,
                       UA_Boolean isDynamic) {
    UA_Node *node =
        UA_NODESTORE_GET_EDIT_SELECTIVE(server, nodeId, 0, UA_REFERENCETYPESET_NONE,
                                        UA_BROWSEDIRECTION_INVALID);
    if(!node)
        return UA_STATUSCODE_BADNODEIDINVALID;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE)
        ((UA_VariableNode*)node)->isDynamic = isDynamic;
    else
        res = UA_STATUSCODE_BADINTERNALERROR;
    UA_NODESTORE_RELEASE(server, node);
    return res;
}

static UA_StatusCode
checkSetIsDynamicVariable(UA_Server *server, UA_Session *session,
                          const UA_NodeId *nodeId) {
    /* Get all hierarchical reference types */
    UA_ReferenceTypeSet reftypes_hierarchical;
    UA_ReferenceTypeSet_init(&reftypes_hierarchical);
    UA_NodeId hierarchicalRefs = UA_NS0ID(HIERARCHICALREFERENCES);
    UA_StatusCode res =
        referenceTypeIndices(server, &hierarchicalRefs, &reftypes_hierarchical, true);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Is the variable under the server object? */
    UA_NodeId serverNodeId = UA_NS0ID(SERVER);
    if(isNodeInTree(server, nodeId, &serverNodeId, &reftypes_hierarchical))
        return UA_STATUSCODE_GOOD;

    /* Is the variable in the type hierarchy? */
    UA_NodeId typesNodeId = UA_NS0ID(TYPESFOLDER);
    if(isNodeInTree(server, nodeId, &typesNodeId, &reftypes_hierarchical))
        return UA_STATUSCODE_GOOD;

    /* Is the variable a property of a method node (InputArguments /
     * OutputArguments)? */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *nodeId;
    bd.browseDirection = UA_BROWSEDIRECTION_INVERSE;
    bd.referenceTypeId = UA_NS0ID(HASPROPERTY);
    bd.includeSubtypes = false;
    bd.nodeClassMask = UA_NODECLASS_METHOD;
    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, session, &maxrefs, &bd, &br);
    UA_Boolean hasParentMethod = (br.referencesSize > 0);
    UA_BrowseResult_clear(&br);
    if(hasParentMethod)
        return UA_STATUSCODE_GOOD;

    /* Set the variable to "dynamic" */
    return setVariableNodeDynamic(server, nodeId, true);
}

UA_StatusCode
UA_Server_setVariableNodeDynamic(UA_Server *server, const UA_NodeId nodeId,
                                 UA_Boolean isDynamic) {
    lockServer(server);
    UA_StatusCode res = setVariableNodeDynamic(server, &nodeId, isDynamic);
    unlockServer(server);
    return res;
}

/* Children, references, type-checking, constructors. */
UA_StatusCode
addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) {
    /* Get the node */
    const UA_Node *type = NULL;
    const UA_Node *node = UA_NODESTORE_GET(server, nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* Set the ReferenceTypesSet of subtypes in the ReferenceTypeNode */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) {
        retval = setReferenceTypeSubtypes(server, &node->referenceTypeNode);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Check NodeClass for 'hasSubtype'. UA_NODECLASS_VARIABLE not allowed
     * to have subtype */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
        for(size_t i = 0; i < node->head.referencesSize; i++) {
            if(node->head.references[i].referenceTypeIndex ==
               UA_REFERENCETYPEINDEX_HASSUBTYPE) {
                UA_LOG_INFO_SESSION(server->config.logging, session,
                                    "AddNode (%N): Variable not allowed "
                                    "to have HasSubType reference",
                                    node->head.nodeId);
                retval = UA_STATUSCODE_BADREFERENCENOTALLOWED;
                goto cleanup;
            }
        }
    }

    /* Set variables to dynamic (source and server timestamps are meaningful) if
     * they fulfill some conditions. (Do this before replacing the default value
     * in a VariableNode. So that the sourceTimestamp is set in the Write service.) */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
        retval = checkSetIsDynamicVariable(server, session, nodeId);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Get the type node
     * TODO: Do we need all attributes and references here?  */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
       node->head.nodeClass == UA_NODECLASS_VARIABLETYPE ||
       node->head.nodeClass == UA_NODECLASS_OBJECT) {
        type = getNodeType(server, &node->head, ~(UA_UInt32)0,
                           UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
        if(!type) {
            if(server->bootstrapNS0)
                goto constructor;
            logAddNode(server->config.logging, session, &node->head.nodeId,
                       "Node type not found");
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }
    }

    /* Initialize and typecheck the variable */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
       node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) {
        /* Use attributes from the type. The value and value constraints are the
         * same for the variable and variabletype attribute structs. */
        retval = useVariableTypeAttributes(server, session,
                                           &node->variableNode,
                                           &type->variableTypeNode);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%N): Using attributes for from "
                                "the variable type failed with error code %s",
                                node->head.nodeId, UA_StatusCode_name(retval));
            goto cleanup;
        }

        /* Get a new pointer to the node. It might have been updated in the
         * background due to a 'Write' operation inside
         * useVariableTypeAttributes. */
        UA_NODESTORE_RELEASE(server, node);
        node = UA_NODESTORE_GET(server, nodeId);
        if(!node || (node->head.nodeClass != UA_NODECLASS_VARIABLE &&
                     node->head.nodeClass != UA_NODECLASS_VARIABLETYPE)) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }

        /* Check if all attributes hold the constraints of the type now. The initial
         * attributes must type-check. The constructor might change the attributes
         * again. Then, the changes are type-checked by the normal write service. */
        retval = typeCheckVariableNode(server, session, &node->variableNode,
                                       &type->variableTypeNode);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%N): Type-checking failed with error code %s",
                                node->head.nodeId, UA_StatusCode_name(retval));
            goto cleanup;
        }
    }

    /* Add (mandatory) child nodes from the type definition */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
       node->head.nodeClass == UA_NODECLASS_OBJECT) {
        retval = addTypeChildren(server, session, nodeId, &type->head.nodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%N): Adding child nodes "
                                "failed with error code %s",
                                node->head.nodeId, UA_StatusCode_name(retval));
            goto cleanup;
        }
    }

    /* Add (mandatory) child nodes from the HasInterface references */
    if(node->head.nodeClass == UA_NODECLASS_OBJECT) {
        retval = addInterfaceChildren(server, session, nodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%N): Adding child nodes "
                                "interface failed with error code %s",
                                node->head.nodeId, UA_StatusCode_name(retval));
            goto cleanup;
        }
    }

    /* Call the constructor(s) */
 constructor:
    if(!node->head.constructed)
        retval = recursiveCallConstructors(server, session, nodeId, type);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%N): Calling the node constructor(s) "
                            "failed with error code %s",
                            node->head.nodeId, UA_StatusCode_name(retval));
    }

 cleanup:
    UA_NODESTORE_RELEASE(server, node);
    if(type)
        UA_NODESTORE_RELEASE(server, type);
    if(retval != UA_STATUSCODE_GOOD)
        deleteNode(server, *nodeId, true);
    return retval;
}

static void
Operation_addNode(UA_Server *server, UA_Session *session, void *nodeContext,
                  const UA_AddNodesItem *item, UA_AddNodesResult *result) {
    result->statusCode =
        Operation_addNode_begin(server, session, nodeContext,
                                item, &item->parentNodeId.nodeId,
                                &item->referenceTypeId, &result->addedNodeId);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* AddNodes_finish */
    result->statusCode = addNode_finish(server, session, &result->addedNodeId);

    /* If finishing failed, the node was deleted */
    if(result->statusCode != UA_STATUSCODE_GOOD)
        UA_NodeId_clear(&result->addedNodeId);
}

UA_Boolean
Service_AddNodes(UA_Server *server, UA_Session *session,
                 const UA_AddNodesRequest *request,
                 UA_AddNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing AddNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->nodesToAddSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_addNode, NULL,
                                      &request->nodesToAddSize,
                                      &UA_TYPES[UA_TYPES_ADDNODESITEM],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
    return true;
}

UA_StatusCode
addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
        const void *attr, const UA_DataType *attributeType,
        void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Create the AddNodesItem */
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = nodeClass;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.parentNodeId.nodeId = parentNodeId;
    item.referenceTypeId = referenceTypeId;
    item.typeDefinition.nodeId = typeDefinition;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes,
                                        (void*)(uintptr_t)attr, attributeType);

    /* Call the normal addnodes service */
    UA_AddNodesResult result;
    UA_AddNodesResult_init(&result);
    Operation_addNode(server, &server->adminSession, nodeContext, &item, &result);
    if(outNewNodeId)
        *outNewNodeId = result.addedNodeId;
    else
        UA_NodeId_clear(&result.addedNodeId);
    return result.statusCode;
}

static UA_StatusCode
__Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                    const UA_NodeId *requestedNewNodeId,
                    const UA_NodeId *parentNodeId,
                    const UA_NodeId *referenceTypeId,
                    const UA_QualifiedName browseName,
                    const UA_NodeId *typeDefinition,
                    const UA_NodeAttributes *attr,
                    const UA_DataType *attributeType,
                    void *nodeContext, UA_NodeId *outNewNodeId) {
    lockServer(server);
    UA_StatusCode reval =
        addNode(server, nodeClass, *requestedNewNodeId, *parentNodeId,
                *referenceTypeId, browseName, *typeDefinition, attr,
                attributeType, nodeContext, outNewNodeId);
    unlockServer(server);
    return reval;
}

UA_StatusCode
UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                          const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                          const UA_VariableAttributes attr, void *nodeContext,
                          UA_NodeId *outNewNodeId) {
    return __Server_addNode(server, UA_NODECLASS_VARIABLE, &requestedNewNodeId,
                            &parentNodeId, &referenceTypeId, browseName,
                            &typeDefinition, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                            nodeContext, outNewNodeId);
}

UA_StatusCode
UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                              const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                              const UA_VariableTypeAttributes attr, void *nodeContext,
                              UA_NodeId *outNewNodeId) {
    return __Server_addNode(server, UA_NODECLASS_VARIABLETYPE,
                            &requestedNewNodeId, &parentNodeId, &referenceTypeId,
                            browseName, &typeDefinition,
                            (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
                            nodeContext, outNewNodeId);
}

UA_StatusCode
UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                        const UA_ObjectAttributes attr, void *nodeContext,
                        UA_NodeId *outNewNodeId) {
    return __Server_addNode(server, UA_NODECLASS_OBJECT, &requestedNewNodeId,
                            &parentNodeId, &referenceTypeId, browseName,
                            &typeDefinition, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                            nodeContext, outNewNodeId);
}

UA_StatusCode
UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                            const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                            const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
                            void *nodeContext, UA_NodeId *outNewNodeId) {
    return __Server_addNode(server, UA_NODECLASS_OBJECTTYPE, &requestedNewNodeId,
                            &parentNodeId, &referenceTypeId, browseName,
                            &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
                            nodeContext, outNewNodeId);
}

UA_StatusCode
UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                      const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                      const UA_QualifiedName browseName, const UA_ViewAttributes attr,
                      void *nodeContext, UA_NodeId *outNewNodeId) {
    return __Server_addNode(server, UA_NODECLASS_VIEW, &requestedNewNodeId,
                            &parentNodeId, &referenceTypeId, browseName,
                            &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_VIEWATTRIBUTES],
                            nodeContext, outNewNodeId);
}

UA_StatusCode
UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                               const UA_QualifiedName browseName,
                               const UA_ReferenceTypeAttributes attr, void *nodeContext,
                               UA_NodeId *outNewNodeId) {
    return __Server_addNode(server, UA_NODECLASS_REFERENCETYPE,
                            &requestedNewNodeId, &parentNodeId, &referenceTypeId,
                            browseName, &UA_NODEID_NULL,
                            (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
                            nodeContext, outNewNodeId);
}

UA_StatusCode
UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                          const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
                          void *nodeContext, UA_NodeId *outNewNodeId) {
    return __Server_addNode(server, UA_NODECLASS_DATATYPE, &requestedNewNodeId,
                            &parentNodeId, &referenceTypeId, browseName,
                            &UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
                            nodeContext, outNewNodeId);
}

UA_StatusCode
addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
              const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
              const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
              const UA_NodeId typeDefinition, const void *attr,
              const UA_DataType *attributeType, void *nodeContext,
              UA_NodeId *outNewNodeId) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = nodeClass;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.typeDefinition.nodeId = typeDefinition;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes,
                                        (void*)(uintptr_t)attr, attributeType);
    return Operation_addNode_begin(server, &server->adminSession, nodeContext, &item,
                                   &parentNodeId, &referenceTypeId, outNewNodeId);
}

UA_StatusCode
UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
                        const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                        const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                        const UA_NodeId typeDefinition, const void *attr,
                        const UA_DataType *attributeType, void *nodeContext,
                        UA_NodeId *outNewNodeId) {
    lockServer(server);
    UA_StatusCode res =
        addNode_begin(server, nodeClass, requestedNewNodeId, parentNodeId,
                      referenceTypeId, browseName, typeDefinition, attr,
                      attributeType, nodeContext, outNewNodeId);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId) {
    lockServer(server);
    UA_StatusCode retval = addNode_finish(server, &server->adminSession, &nodeId);
    unlockServer(server);
    return retval;
}

/****************/
/* Delete Nodes */
/****************/

static void
Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
                          const UA_DeleteReferencesItem *item, UA_StatusCode *retval);

struct RemoveIncomingContext {
    UA_Server *server;
    UA_Session *session;
    UA_DeleteReferencesItem *item;
};

static void *
removeIncomingReferencesCallback(void *context, UA_ReferenceTarget *t) {
    struct RemoveIncomingContext *ctx = (struct RemoveIncomingContext *)context;
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;
    UA_StatusCode dummy;
    ctx->item->sourceNodeId = UA_NodePointer_toNodeId(t->targetId);
    Operation_deleteReference(ctx->server, ctx->session, NULL, ctx->item, &dummy);
    return NULL;
}

/* Remove references to this node (in the other nodes) */
static void
removeIncomingReferences(UA_Server *server, UA_Session *session,
                         const UA_NodeHead *head) {
    UA_DeleteReferencesItem item;
    UA_DeleteReferencesItem_init(&item);
    item.targetNodeId.nodeId = head->nodeId;
    item.deleteBidirectional = false;

    struct RemoveIncomingContext ctx;
    ctx.server = server;
    ctx.session = session;
    ctx.item = &item;

    for(size_t i = 0; i < head->referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];
        item.isForward = rk->isInverse;
        item.referenceTypeId =
            *UA_NODESTORE_GETREFERENCETYPEID(server, rk->referenceTypeIndex);
        UA_NodeReferenceKind_iterate(rk, removeIncomingReferencesCallback, &ctx);
    }
}

static void *
checkTargetInRefTree(void *context, UA_ReferenceTarget *t) {
    RefTree *refTree = (RefTree*)context;
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;
    UA_NodeId tmpId = UA_NodePointer_toNodeId(t->targetId);
    if(!RefTree_containsNodeId(refTree, &tmpId))
        return (void*)0x1;
    return NULL;
}

/* A node is auto-deleted if all its hierarchical parents are being deleted */
static UA_Boolean
hasParentRef(const UA_NodeHead *head, const UA_ReferenceTypeSet *refSet,
             RefTree *refTree) {
    for(size_t i = 0; i < head->referencesSize; i++) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(!rk->isInverse)
            continue;
        if(!UA_ReferenceTypeSet_contains(refSet, rk->referenceTypeIndex))
            continue;
        if(UA_NodeReferenceKind_iterate(rk, checkTargetInRefTree, refTree) != NULL)
            return true;
    }
    return false;
}

static void
deconstructNodeSet(UA_Server *server, UA_Session *session,
                   UA_ReferenceTypeSet *hierarchRefsSet, RefTree *refTree) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Deconstruct the nodes based on the RefTree entries, parent nodes first */
    for(size_t i = 0; i < refTree->size; i++) {
        const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[i].nodeId);
        if(!member)
            continue;

        /* Call the type-level destructor
         * TODO: Do we need all attributes and references here?  */
        void *context = member->head.context; /* No longer needed after this function */
        if(member->head.nodeClass == UA_NODECLASS_OBJECT ||
           member->head.nodeClass == UA_NODECLASS_VARIABLE) {
            const UA_Node *type =
                getNodeType(server, &member->head, ~(UA_UInt32)0,
                            UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
            if(type) {
               /* Get the lifecycle */
               const UA_NodeTypeLifecycle *lifecycle;
               if(member->head.nodeClass == UA_NODECLASS_OBJECT)
                  lifecycle = &type->objectTypeNode.lifecycle;
               else
                  lifecycle = &type->variableTypeNode.lifecycle;

               /* Call the destructor */
               if(lifecycle->destructor) {
                  lifecycle->destructor(server,
                                        &session->sessionId, session->context,
                                        &type->head.nodeId, type->head.context,
                                        &member->head.nodeId, &context);
               }

               /* Release the type node */
               UA_NODESTORE_RELEASE(server, type);
            }
        }

        /* Call the global destructor */
        if(server->config.nodeLifecycle &&
           server->config.nodeLifecycle->destructor) {
            server->config.nodeLifecycle->destructor(server, &session->sessionId,
                                                     session->context,
                                                     &member->head.nodeId, context);
        }

        /* Release the node. Don't access the node context from here on. */
        UA_NODESTORE_RELEASE(server, member);

        /* Set the constructed flag to false */
        editNode(server, &server->adminSession, &refTree->targets[i].nodeId,
                 0, UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                 (UA_EditNodeCallback)setDeconstructedNode, NULL);
    }
}

struct DeleteChildrenContext {
    UA_Server *server;
    const UA_ReferenceTypeSet *hierarchRefsSet;
    RefTree *refTree;
    UA_StatusCode res;
};

static void *
deleteChildrenCallback(void *context, UA_ReferenceTarget *t) {
    struct DeleteChildrenContext *ctx = (struct DeleteChildrenContext*)context;

    /* Get the child */
    const UA_Node *child = UA_NODESTORE_GETFROMREF(ctx->server, t->targetId);
    if(!child)
        return NULL;

    /* Only delete child nodes that have no other parent */
    if(!hasParentRef(&child->head, ctx->hierarchRefsSet, ctx->refTree))
        ctx->res = RefTree_addNodeId(ctx->refTree, &child->head.nodeId, NULL);

    UA_NODESTORE_RELEASE(ctx->server, child);
    return (ctx->res == UA_STATUSCODE_GOOD) ? NULL : (void*)0x01;
}

/* The processNodeLayer function searches all children's of the head node and
 * adds the children node to the RefTree if all incoming references sources are
 * contained in the RefTree (No callback references to this node --> node can be
 * deleted) */
static UA_StatusCode
autoDeleteChildren(UA_Server *server, UA_Session *session, RefTree *refTree,
                   const UA_ReferenceTypeSet *hierarchRefsSet, const UA_NodeHead *head){
    struct DeleteChildrenContext ctx;
    ctx.server = server;
    ctx.hierarchRefsSet = hierarchRefsSet;
    ctx.refTree = refTree;
    ctx.res = UA_STATUSCODE_GOOD;

    for(size_t i = 0; i < head->referencesSize; ++i) {
        /* Check if the ReferenceType is hierarchical */
        UA_NodeReferenceKind *rk = &head->references[i];
        if(!UA_ReferenceTypeSet_contains(hierarchRefsSet, rk->referenceTypeIndex))
            continue;

        /* Check if the references are forward (to a child) */
        if(rk->isInverse)
            continue;

        /* Loop over the references */
        UA_NodeReferenceKind_iterate(rk, deleteChildrenCallback, &ctx);
        if(ctx.res != UA_STATUSCODE_GOOD)
            return ctx.res;
    }
    return UA_STATUSCODE_GOOD;
}

/* Build up an ordered set (tree) of all nodes that can be deleted. Step through
 * the ordered set in order to avoid recursion. */
static UA_StatusCode
buildDeleteNodeSet(UA_Server *server, UA_Session *session,
                   const UA_ReferenceTypeSet *hierarchRefsSet,
                   const UA_NodeId *initial, UA_Boolean removeTargetRefs,
                   RefTree *refTree) {
    /* Add the initial node to delete */
    UA_StatusCode res = RefTree_addNodeId(refTree, initial, NULL);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Find out which hierarchical children should also be deleted. We know
     * there are no "callback" ExpandedNodeId in the RefTree. */
    size_t pos = 0;
    while(pos < refTree->size) {
        const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[pos].nodeId);
        pos++;
        if(!member)
            continue;
        res |= autoDeleteChildren(server, session, refTree, hierarchRefsSet, &member->head);
        UA_NODESTORE_RELEASE(server, member);
    }
    return res;
}

static void
deleteNodeSet(UA_Server *server, UA_Session *session,
              const UA_ReferenceTypeSet *hierarchRefsSet,
              UA_Boolean removeTargetRefs, RefTree *refTree) {
    /* Delete the nodes based on the RefTree entries */
    for(size_t i = refTree->size; i > 0; --i) {
        const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[i-1].nodeId);
        if(!member)
            continue;
        UA_NODESTORE_RELEASE(server, member);
        if(removeTargetRefs)
            removeIncomingReferences(server, session, &member->head);
        UA_NODESTORE_REMOVE(server, &member->head.nodeId);
    }
}

static void
deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
                    const UA_DeleteNodesItem *item, UA_StatusCode *result) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Do not check access for server */
    if(session != &server->adminSession && server->config.accessControl.allowDeleteNode) {
        if(!server->config.accessControl.
           allowDeleteNode(server, &server->config.accessControl,
                           &session->sessionId, session->context, item)) {
            *result = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
    }

    const UA_Node *node = UA_NODESTORE_GET(server, &item->nodeId);
    if(!node) {
        *result = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return;
    }

    if(UA_Node_hasSubTypeOrInstances(&node->head)) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "DeleteNode (%N): Cannot delete a type node with "
                            "active instances or subtypes", node->head.nodeId);
        UA_NODESTORE_RELEASE(server, node);
        *result = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* TODO: Check if the information model consistency is violated */
    /* TODO: Check if the node is a mandatory child of a parent */

    /* Relase the node. Don't access the pointer after this! */
    UA_NODESTORE_RELEASE(server, node);

    /* A node can be referenced with hierarchical references from several
     * parents in the information model. (But not in a circular way.) The
     * hierarchical references are checked to see if a node can be deleted.
     * Getting the type hierarchy can fail in case of low RAM. In that case the
     * nodes are always deleted. */
    UA_ReferenceTypeSet hierarchRefsSet;
    UA_NodeId hr = UA_NS0ID(HIERARCHICALREFERENCES);
    *result = referenceTypeIndices(server, &hr, &hierarchRefsSet, true);
    if(*result != UA_STATUSCODE_GOOD)
        return;

    /* The list of childs is needed for the deconstructing and deleting phase.
     * Within the processNodeLayer we generate a RefTree based set of childs
     * which can be deleted beside the parent node. */
    RefTree refTree;
    *result = RefTree_init(&refTree);
    if(*result != UA_STATUSCODE_GOOD)
        return;
    *result = buildDeleteNodeSet(server, session, &hierarchRefsSet, &item->nodeId,
                                 item->deleteTargetReferences, &refTree);
    if(*result != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "DeleteNode: Incomplete lookup of nodes. "
                               "Still deleting what we have.");
        /* Continue, so the RefTree is cleaned up. Return the error message
         * anyway. */
    }

    /* Deconstruct, then delete, then clean up the set */
    deconstructNodeSet(server, session, &hierarchRefsSet, &refTree);
    deleteNodeSet(server, session, &hierarchRefsSet,
                  item->deleteTargetReferences, &refTree);
    RefTree_clear(&refTree);
}

UA_Boolean
Service_DeleteNodes(UA_Server *server, UA_Session *session,
                    const UA_DeleteNodesRequest *request,
                    UA_DeleteNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->nodesToDeleteSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)deleteNodeOperation,
                                      NULL, &request->nodesToDeleteSize,
                                      &UA_TYPES[UA_TYPES_DELETENODESITEM],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_STATUSCODE]);
    return true;
}

UA_StatusCode
UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
                     UA_Boolean deleteReferences) {
    lockServer(server);
    UA_StatusCode retval = deleteNode(server, nodeId, deleteReferences);
    unlockServer(server);
    return retval;
}

UA_StatusCode
deleteNode(UA_Server *server, const UA_NodeId nodeId,
           UA_Boolean deleteReferences) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_DeleteNodesItem item;
    item.deleteTargetReferences = deleteReferences;
    item.nodeId = nodeId;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    deleteNodeOperation(server, &server->adminSession, NULL, &item, &retval);
    return retval;
}

/******************/
/* Add References */
/******************/

static void
Operation_addReference(UA_Server *server, UA_Session *session, void *context,
                       const UA_AddReferencesItem *item, UA_StatusCode *retval) {
    (void)context;
    UA_assert(session);
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Check access rights */
    if(session != &server->adminSession && server->config.accessControl.allowAddReference) {
        if (!server->config.accessControl.
                allowAddReference(server, &server->config.accessControl,
                                  &session->sessionId, session->context, item)) {
            *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
    }

    /* TODO: Currently no expandednodeids are allowed */
    if(item->targetServerUri.length > 0) {
        *retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
        return;
    }

    /* Check the ReferenceType and get the index */
    const UA_Node *refType = UA_NODESTORE_GET(server, &item->referenceTypeId);
    if(!refType) {
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Cannot add reference - ReferenceType %N unknown",
                             item->referenceTypeId);
        *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
        return;
    }
    if(refType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Cannot add reference - ReferenceType %N with wrong NodeClass",
                             item->referenceTypeId);
        UA_NODESTORE_RELEASE(server, refType);
        *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
        return;
    }
    UA_Byte refTypeIndex = refType->referenceTypeNode.referenceTypeIndex;
    UA_NODESTORE_RELEASE(server, refType);

    /* Get the source and target node (editable). Include only the BrowseName
     * and the relevant ReferenceType and direction. Don't modify the target
     * node if it lives on a different server. */
    UA_Node *targetNode = NULL;
    if(UA_ExpandedNodeId_isLocal(&item->targetNodeId)) {
        if(UA_NodeId_equal(&item->targetNodeId.nodeId, &item->sourceNodeId)) {
            *retval = UA_STATUSCODE_GOOD;
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "Cannot add reference - source and target %N are identical",
                                item->targetNodeId.nodeId);
            return;
        }
        targetNode =
            UA_NODESTORE_GET_EDIT_SELECTIVE(server, &item->targetNodeId.nodeId,
                                            UA_NODEATTRIBUTESMASK_BROWSENAME,
                                            UA_REFTYPESET(refTypeIndex),
                                            (!item->isForward) ?
                                            UA_BROWSEDIRECTION_FORWARD : UA_BROWSEDIRECTION_INVERSE);
        if(!targetNode) {
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "Cannot add reference - target %N does not exist",
                                 item->targetNodeId.nodeId);
            *retval = UA_STATUSCODE_BADTARGETNODEIDINVALID;
            return;
        }
        if(item->targetNodeClass != UA_NODECLASS_UNSPECIFIED &&
           item->targetNodeClass != targetNode->head.nodeClass) {
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "Cannot add reference - target %N has NodeClass %u "
                                 "but request expects %u",
                                 item->targetNodeId.nodeId, (unsigned)targetNode->head.nodeClass,
                                 (unsigned)item->targetNodeClass);
            UA_NODESTORE_RELEASE(server, targetNode);
            *retval = UA_STATUSCODE_BADNODECLASSINVALID;
            return;
        }
    }

    UA_Node *sourceNode =
        UA_NODESTORE_GET_EDIT_SELECTIVE(server, &item->sourceNodeId,
                                        UA_NODEATTRIBUTESMASK_BROWSENAME,
                                        UA_REFTYPESET(refTypeIndex),
                                        item->isForward ?
                                        UA_BROWSEDIRECTION_FORWARD : UA_BROWSEDIRECTION_INVERSE);
    if(!sourceNode) {
        if(targetNode)
            UA_NODESTORE_RELEASE(server, targetNode);
        *retval = UA_STATUSCODE_BADSOURCENODEIDINVALID;
        return;
    }

    /* Add the first direction */
    UA_UInt32 targetNameHash = UA_QualifiedName_hash(&targetNode->head.browseName);
    *retval = UA_Node_addReference(sourceNode, refTypeIndex, item->isForward,
                                   &item->targetNodeId, targetNameHash);
    UA_Boolean firstExisted = false;
    if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
        *retval = UA_STATUSCODE_GOOD;
        firstExisted = true;
    }
    if(*retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Add the second direction */
    if(targetNode) {
        UA_ExpandedNodeId expSourceId;
        UA_ExpandedNodeId_init(&expSourceId);
        expSourceId.nodeId = item->sourceNodeId;
        UA_UInt32 sourceNameHash = UA_QualifiedName_hash(&sourceNode->head.browseName);
        *retval = UA_Node_addReference(targetNode, refTypeIndex, !item->isForward,
                                       &expSourceId, sourceNameHash);

        /* Second direction existed already */
        if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
            /* Set bad result if BOTH directions already existed.
             * But don't delete the reference from source to target. */
            if(!firstExisted)
                *retval = UA_STATUSCODE_GOOD;
            goto cleanup;
        }

        /* Remove first direction if the second direction failed */
        if(*retval != UA_STATUSCODE_GOOD)
            UA_Node_deleteReference(sourceNode, refTypeIndex, item->isForward, &item->targetNodeId);
    }

 cleanup:
    if(targetNode)
        UA_NODESTORE_RELEASE(server, targetNode);
    UA_NODESTORE_RELEASE(server, sourceNode);
}

UA_Boolean
Service_AddReferences(UA_Server *server, UA_Session *session,
                      const UA_AddReferencesRequest *request,
                      UA_AddReferencesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing AddReferencesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_assert(session);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->referencesToAddSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_addReference,
                                      NULL, &request->referencesToAddSize,
                                      &UA_TYPES[UA_TYPES_ADDREFERENCESITEM],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_STATUSCODE]);
    return true;
}

UA_StatusCode
UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
                       const UA_NodeId refTypeId,
                       const UA_ExpandedNodeId targetId,
                       UA_Boolean isForward) {
    UA_AddReferencesItem item;
    UA_AddReferencesItem_init(&item);
    item.sourceNodeId = sourceId;
    item.referenceTypeId = refTypeId;
    item.isForward = isForward;
    item.targetNodeId = targetId;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    lockServer(server);
    Operation_addReference(server, &server->adminSession, NULL, &item, &retval);
    unlockServer(server);
    return retval;
}

/*********************/
/* Delete References */
/*********************/

static void
Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
                          const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Do not check access for server */
    if(session != &server->adminSession &&
       server->config.accessControl.allowDeleteReference) {
        if(!server->config.accessControl.
           allowDeleteReference(server, &server->config.accessControl,
                                &session->sessionId, session->context, item)) {
            *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
    }

    /* Check the ReferenceType and get the RefTypeIndex */
    const UA_Node *refType =
        UA_NODESTORE_GET_SELECTIVE(server, &item->referenceTypeId,
                                   0, UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID);
    if(!refType) {
        *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
        return;
    }

    if(refType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        UA_NODESTORE_RELEASE(server, refType);
        *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
        return;
    }

    UA_Byte refTypeIndex = refType->referenceTypeNode.referenceTypeIndex;
    UA_NODESTORE_RELEASE(server, refType);

    // TODO: Check consistency constraints, remove the references.

    /* Delete the reference in this direction */
    UA_Node *firstNode =
        UA_NODESTORE_GET_EDIT_SELECTIVE(server, &item->sourceNodeId, 0,
                                        UA_REFTYPESET(refTypeIndex),
                                        item->isForward ?
                                        UA_BROWSEDIRECTION_FORWARD : UA_BROWSEDIRECTION_INVERSE);
    if(firstNode) {
        *retval = UA_Node_deleteReference(firstNode, refTypeIndex, item->isForward, &item->targetNodeId);
    } else {
        *retval = UA_STATUSCODE_BADNODEIDUNKNOWN;
    }
    UA_NODESTORE_RELEASE(server, firstNode);
    if(*retval != UA_STATUSCODE_GOOD)
        return;

    if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
        return;

    /* Remove the reference in the second direction */
    if(UA_ExpandedNodeId_isLocal(&item->targetNodeId)) {
        UA_ExpandedNodeId target2;
        UA_ExpandedNodeId_init(&target2);
        target2.nodeId = item->sourceNodeId;
        UA_Node *secondNode =
            UA_NODESTORE_GET_EDIT_SELECTIVE(server, &item->targetNodeId.nodeId, 0,
                                            UA_REFTYPESET(refTypeIndex),
                                            (!item->isForward) ?
                                            UA_BROWSEDIRECTION_FORWARD : UA_BROWSEDIRECTION_INVERSE);
        if(secondNode) {
            *retval = UA_Node_deleteReference(secondNode, refTypeIndex, !item->isForward, &target2);
            UA_NODESTORE_RELEASE(server, secondNode);
        }
    }
}

UA_Boolean
Service_DeleteReferences(UA_Server *server, UA_Session *session,
                         const UA_DeleteReferencesRequest *request,
                         UA_DeleteReferencesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteReferencesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->referencesToDeleteSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return true;
    }

    response->responseHeader.serviceResult =
        allocProcessServiceOperations(server, session,
                                      (UA_ServiceOperation)Operation_deleteReference,
                                      NULL, &request->referencesToDeleteSize,
                                      &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM],
                                      &response->resultsSize,
                                      &UA_TYPES[UA_TYPES_STATUSCODE]);
    return true;
}

UA_StatusCode
deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                const UA_NodeId referenceTypeId, UA_Boolean isForward,
                const UA_ExpandedNodeId targetNodeId,
                UA_Boolean deleteBidirectional) {
    UA_DeleteReferencesItem item;
    item.sourceNodeId = sourceNodeId;
    item.referenceTypeId = referenceTypeId;
    item.isForward = isForward;
    item.targetNodeId = targetNodeId;
    item.deleteBidirectional = deleteBidirectional;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    Operation_deleteReference(server, &server->adminSession, NULL, &item, &retval);
    return retval;
}

UA_StatusCode
UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                          const UA_NodeId referenceTypeId, UA_Boolean isForward,
                          const UA_ExpandedNodeId targetNodeId,
                          UA_Boolean deleteBidirectional) {
    lockServer(server);
    UA_StatusCode res = deleteReference(server, sourceNodeId, referenceTypeId,
                                        isForward, targetNodeId, deleteBidirectional);
    unlockServer(server);
    return res;
}

/*****************************/
/* Set Internal Value Source */
/*****************************/

struct SetInternalValueContext {
    const UA_DataValue *value;
    const UA_ValueSourceNotifications *notifications;
};

static UA_StatusCode
setInternalValueSourceCB(UA_Server *server, UA_Session *session,
                         UA_VariableNode *vn, const void *ctx) {
    const struct SetInternalValueContext *ivc =
        (const struct SetInternalValueContext*)ctx;

    /* Check the node class */
    if(vn->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADNODECLASSINVALID;

    /* Make a copy of the supplied value */
    UA_DataValue val;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ivc->value) {
        res = UA_DataValue_copy(ivc->value, &val);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Replace the previous internal value */
    if(vn->valueSourceType == UA_VALUESOURCETYPE_INTERNAL) {
        if(ivc->value) {
            UA_DataValue_clear(&vn->valueSource.internal.value);
            vn->valueSource.internal.value = val;
        }
    } else {
        if(ivc->value)
            vn->valueSource.internal.value = val;
        else
            UA_DataValue_init(&vn->valueSource.internal.value);
        vn->valueSourceType = UA_VALUESOURCETYPE_INTERNAL;
    }

    /* Set the notification callbacks */
    if(ivc->notifications)
        vn->valueSource.internal.notifications = *ivc->notifications;
    else
        memset(&vn->valueSource.internal.notifications, 0,
               sizeof(UA_ValueSourceNotifications));

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setVariableNode_internalValueSource(UA_Server *server, const UA_NodeId nodeId,
                                    const UA_DataValue *value,
                                    const UA_ValueSourceNotifications *notifications) {
    struct SetInternalValueContext ctx;
    ctx.value = value;
    ctx.notifications = notifications;
    return editNode(server, &server->adminSession, &nodeId,
                    UA_NODEATTRIBUTESMASK_VALUE, UA_REFERENCETYPESET_NONE,
                    UA_BROWSEDIRECTION_INVALID,
                    (UA_EditNodeCallback)setInternalValueSourceCB, &ctx);
}

UA_StatusCode
UA_Server_setVariableNode_internalValueSource(UA_Server *server, const UA_NodeId nodeId,
                                              const UA_DataValue *value,
                                              const UA_ValueSourceNotifications *notifications) {
    lockServer(server);
    UA_StatusCode res = setVariableNode_internalValueSource(server, nodeId, value, notifications);
    unlockServer(server);
    return res;
}

/*****************************/
/* Set External Value Source */
/*****************************/

struct SetExternalValueContext {
    UA_DataValue **value;
    const UA_ValueSourceNotifications *notifications;
};

static UA_StatusCode
setExternalValueSourceCB(UA_Server *server, UA_Session *session,
                         UA_VariableNode *vn, const void *ctx) {
    const struct SetExternalValueContext *evc =
        (const struct SetExternalValueContext*)ctx;

    /* Check the node class */
    if(vn->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADNODECLASSINVALID;

    /* Clean the previous internal value */
    if(vn->valueSourceType == UA_VALUESOURCETYPE_INTERNAL && evc->value)
        UA_DataValue_clear(&vn->valueSource.internal.value);

    /* Set the value */
    vn->valueSourceType = UA_VALUESOURCETYPE_EXTERNAL;
    vn->valueSource.external.value = evc->value;
    if(evc->notifications)
        vn->valueSource.external.notifications = *evc->notifications;
    else
        memset(&vn->valueSource.external.notifications, 0,
               sizeof(UA_ValueSourceNotifications));

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_setVariableNode_externalValueSource(UA_Server *server, const UA_NodeId nodeId,
                                              UA_DataValue **value,
                                              const UA_ValueSourceNotifications *notifications) {
    if(!server || !value || !*value)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    struct SetExternalValueContext ctx;
    ctx.value = value;
    ctx.notifications = notifications;
    UA_StatusCode res = editNode(server, &server->adminSession, &nodeId,
                                 UA_NODEATTRIBUTESMASK_VALUE, UA_REFERENCETYPESET_NONE,
                                 UA_BROWSEDIRECTION_INVALID,
                                 (UA_EditNodeCallback)setExternalValueSourceCB, &ctx);
    unlockServer(server);
    return res;
}

/*****************************/
/* Set Callback Value Source */
/*****************************/

static UA_StatusCode
setCallbackValueSourceCB(UA_Server *server, UA_Session *session,
                         UA_VariableNode *vn, const void *ctx) {
    const UA_CallbackValueSource *evs = (const UA_CallbackValueSource*)ctx;

    /* Check the node class */
    if(vn->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADNODECLASSINVALID;

    /* Clean up the internal value */
    if(vn->valueSourceType == UA_VALUESOURCETYPE_INTERNAL)
        UA_DataValue_clear(&vn->valueSource.internal.value);

    /* Replace the value source */
    vn->valueSource.callback = *evs;
    vn->valueSourceType = UA_VALUESOURCETYPE_CALLBACK;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setVariableNode_callbackValueSource(UA_Server *server, const UA_NodeId nodeId,
                                    const UA_CallbackValueSource evs) {
    return editNode(server, &server->adminSession, &nodeId, UA_NODEATTRIBUTESMASK_VALUE,
                    UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                    (UA_EditNodeCallback)setCallbackValueSourceCB,
                    (void*)(uintptr_t)&evs);
}

UA_StatusCode
UA_Server_setVariableNode_callbackValueSource(UA_Server *server,
                                              const UA_NodeId nodeId,
                                              const UA_CallbackValueSource evs) {
    lockServer(server);
    UA_StatusCode res = setVariableNode_callbackValueSource(server, nodeId, evs);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_addCallbackValueSourceVariableNode(UA_Server *server,
                                             const UA_NodeId requestedNewNodeId,
                                             const UA_NodeId parentNodeId,
                                             const UA_NodeId referenceTypeId,
                                             const UA_QualifiedName browseName,
                                             const UA_NodeId typeDefinition,
                                             const UA_VariableAttributes attr,
                                             const UA_CallbackValueSource evs,
                                             void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = UA_NODECLASS_VARIABLE;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    UA_ExpandedNodeId typeDefinitionId;
    UA_ExpandedNodeId_init(&typeDefinitionId);
    typeDefinitionId.nodeId = typeDefinition;
    item.typeDefinition = typeDefinitionId;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, (void*)(uintptr_t)&attr,
                                        &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]);
    UA_NodeId newNodeId;
    if(!outNewNodeId) {
        newNodeId = UA_NODEID_NULL;
        outNewNodeId = &newNodeId;
    }

    lockServer(server);

    /* Create the node and add it to the nodestore */
    UA_StatusCode retval = addNode_raw(server, &server->adminSession, nodeContext,
                                       &item, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Set the value source */
    retval = setVariableNode_callbackValueSource(server, *outNewNodeId, evs);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Typecheck and add references to parent and type definition */
    retval = addNode_addRefs(server, &server->adminSession, outNewNodeId, &parentNodeId,
                             &referenceTypeId, &typeDefinition);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Call the constructors */
    retval = addNode_finish(server, &server->adminSession, outNewNodeId);

 cleanup:
    unlockServer(server);
    if(outNewNodeId == &newNodeId)
        UA_NodeId_clear(&newNodeId);

    return retval;
}

/************************************/
/* Special Handling of Method Nodes */
/************************************/

#ifdef UA_ENABLE_METHODCALLS

static const UA_NodeId hasproperty = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASPROPERTY}};
static const UA_NodeId propertytype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_PROPERTYTYPE}};

static UA_StatusCode
UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
                                 UA_MethodCallback method,
                                 const size_t inputArgumentsSize,
                                 const UA_Argument *inputArguments,
                                 const UA_NodeId inputArgumentsRequestedNewNodeId,
                                 UA_NodeId *inputArgumentsOutNewNodeId,
                                 const size_t outputArgumentsSize,
                                 const UA_Argument *outputArguments,
                                 const UA_NodeId outputArgumentsRequestedNewNodeId,
                                 UA_NodeId *outputArgumentsOutNewNodeId) {
    /* Browse to see which argument nodes exist */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = nodeId;
    bd.referenceTypeId = UA_NS0ID(HASPROPERTY);
    bd.includeSubtypes = false;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
    bd.nodeClassMask = UA_NODECLASS_VARIABLE;
    bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;

    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, &server->adminSession, &maxrefs, &bd, &br);

    UA_StatusCode retval = br.statusCode;
    if(retval != UA_STATUSCODE_GOOD) {
        deleteNode(server, nodeId, true);
        UA_BrowseResult_clear(&br);
        return retval;
    }

    /* Filter out the argument nodes */
    UA_NodeId inputArgsId = UA_NODEID_NULL;
    UA_NodeId outputArgsId = UA_NODEID_NULL;
    const UA_QualifiedName inputArgsName = UA_QUALIFIEDNAME(0, "InputArguments");
    const UA_QualifiedName outputArgsName = UA_QUALIFIEDNAME(0, "OutputArguments");
    for(size_t i = 0; i < br.referencesSize; i++) {
        UA_ReferenceDescription *rd = &br.references[i];
        if(rd->browseName.namespaceIndex == 0 &&
           UA_String_equal(&rd->browseName.name, &inputArgsName.name))
            inputArgsId = rd->nodeId.nodeId;
        else if(rd->browseName.namespaceIndex == 0 &&
                UA_String_equal(&rd->browseName.name, &outputArgsName.name))
            outputArgsId = rd->nodeId.nodeId;
    }

    /* Add the Input Arguments VariableNode */
    if(inputArgumentsSize > 0 && UA_NodeId_isNull(&inputArgsId)) {
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        char *name = "InputArguments";
        attr.displayName = UA_LOCALIZEDTEXT("", name);
        attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
        attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
        UA_UInt32 inputArgsSize32 = (UA_UInt32)inputArgumentsSize;
        attr.arrayDimensions = &inputArgsSize32;
        attr.arrayDimensionsSize = 1;
        UA_Variant_setArray(&attr.value, (void *)(uintptr_t)inputArguments,
                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
        retval = addNode(server, UA_NODECLASS_VARIABLE, inputArgumentsRequestedNewNodeId,
                         nodeId, hasproperty, UA_QUALIFIEDNAME(0, name),
                         propertytype, &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                         NULL, &inputArgsId);
        if(retval != UA_STATUSCODE_GOOD)
            goto error;
    }

    /* Add the Output Arguments VariableNode */
    if(outputArgumentsSize > 0 && UA_NodeId_isNull(&outputArgsId)) {
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        char *name = "OutputArguments";
        attr.displayName = UA_LOCALIZEDTEXT("", name);
        attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
        attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
        UA_UInt32 outputArgsSize32 = (UA_UInt32)outputArgumentsSize;
        attr.arrayDimensions = &outputArgsSize32;
        attr.arrayDimensionsSize = 1;
        UA_Variant_setArray(&attr.value, (void *)(uintptr_t)outputArguments,
                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
        retval = addNode(server, UA_NODECLASS_VARIABLE, outputArgumentsRequestedNewNodeId,
                         nodeId, hasproperty, UA_QUALIFIEDNAME(0, name),
                         propertytype, &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                         NULL, &outputArgsId);
        if(retval != UA_STATUSCODE_GOOD)
            goto error;
    }

    retval = setMethodNode_callback(server, nodeId, method);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    /* Call finish to add the parent reference */
    retval = addNode_finish(server, &server->adminSession, &nodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    if(inputArgumentsOutNewNodeId != NULL) {
        UA_NodeId_copy(&inputArgsId, inputArgumentsOutNewNodeId);
    }
    if(outputArgumentsOutNewNodeId != NULL) {
        UA_NodeId_copy(&outputArgsId, outputArgumentsOutNewNodeId);
    }
    UA_BrowseResult_clear(&br);
    return retval;

error:
    deleteNode(server, nodeId, true);
    deleteNode(server, inputArgsId, true);
    deleteNode(server, outputArgsId, true);
    UA_BrowseResult_clear(&br);
    return retval;
}

UA_StatusCode
UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
                               UA_MethodCallback method,
                               size_t inputArgumentsSize,
                               const UA_Argument* inputArguments,
                               size_t outputArgumentsSize,
                               const UA_Argument* outputArguments) {
    lockServer(server);
    UA_StatusCode retval =
        UA_Server_addMethodNodeEx_finish(server, nodeId, method,
                                         inputArgumentsSize, inputArguments,
                                         UA_NODEID_NULL, NULL,
                                         outputArgumentsSize, outputArguments,
                                         UA_NODEID_NULL, NULL);
    unlockServer(server);
    return retval;
}

UA_StatusCode
addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
              const UA_QualifiedName browseName,
              const UA_MethodAttributes *attr, UA_MethodCallback method,
              size_t inputArgumentsSize, const UA_Argument *inputArguments,
              const UA_NodeId inputArgumentsRequestedNewNodeId,
              UA_NodeId *inputArgumentsOutNewNodeId,
              size_t outputArgumentsSize, const UA_Argument *outputArguments,
              const UA_NodeId outputArgumentsRequestedNewNodeId,
              UA_NodeId *outputArgumentsOutNewNodeId,
              void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = UA_NODECLASS_METHOD;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, (void*)(uintptr_t)attr,
                                        &UA_TYPES[UA_TYPES_METHODATTRIBUTES]);
    UA_NodeId newId;
    if(!outNewNodeId) {
        UA_NodeId_init(&newId);
        outNewNodeId = &newId;
    }
    UA_StatusCode retval = Operation_addNode_begin(server, &server->adminSession,
                                                   nodeContext, &item, &parentNodeId,
                                                   &referenceTypeId, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_Server_addMethodNodeEx_finish(server, *outNewNodeId, method,
                                              inputArgumentsSize, inputArguments,
                                              inputArgumentsRequestedNewNodeId,
                                              inputArgumentsOutNewNodeId,
                                              outputArgumentsSize, outputArguments,
                                              outputArgumentsRequestedNewNodeId,
                                              outputArgumentsOutNewNodeId);
    if(outNewNodeId == &newId)
        UA_NodeId_clear(&newId);
    return retval;
}

UA_StatusCode
UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId,
                          const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId,
                          const UA_QualifiedName browseName,
                          const UA_MethodAttributes attr, UA_MethodCallback method,
                          size_t inputArgumentsSize, const UA_Argument *inputArguments,
                          const UA_NodeId inputArgumentsRequestedNewNodeId,
                          UA_NodeId *inputArgumentsOutNewNodeId,
                          size_t outputArgumentsSize, const UA_Argument *outputArguments,
                          const UA_NodeId outputArgumentsRequestedNewNodeId,
                          UA_NodeId *outputArgumentsOutNewNodeId,
                          void *nodeContext, UA_NodeId *outNewNodeId) {
    lockServer(server);
    UA_StatusCode res = addMethodNode(server, requestedNewNodeId,
                                      parentNodeId, referenceTypeId,
                                      browseName, &attr, method,
                                      inputArgumentsSize, inputArguments,
                                      inputArgumentsRequestedNewNodeId,
                                      inputArgumentsOutNewNodeId,
                                      outputArgumentsSize,
                                      outputArguments,
                                      outputArgumentsRequestedNewNodeId,
                                      outputArgumentsOutNewNodeId,
                                      nodeContext, outNewNodeId);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                        const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                        UA_MethodCallback method,
                        size_t inputArgumentsSize, const UA_Argument *inputArguments,
                        size_t outputArgumentsSize, const UA_Argument *outputArguments,
                        void *nodeContext, UA_NodeId *outNewNodeId) {
    return UA_Server_addMethodNodeEx(server, requestedNewNodeId,  parentNodeId,
                                     referenceTypeId, browseName, attr, method,
                                     inputArgumentsSize, inputArguments,
                                     UA_NODEID_NULL, NULL,
                                     outputArgumentsSize, outputArguments,
                                     UA_NODEID_NULL, NULL,
                                     nodeContext, outNewNodeId);
}

static UA_StatusCode
editMethodCallback(UA_Server *server, UA_Session* session,
                   UA_Node *node, UA_MethodCallback methodCallback) {
    if(node->head.nodeClass != UA_NODECLASS_METHOD)
        return UA_STATUSCODE_BADNODECLASSINVALID;
    node->methodNode.method = methodCallback;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setMethodNode_callback(UA_Server *server,
                       const UA_NodeId methodNodeId,
                       UA_MethodCallback methodCallback) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    return editNode(server, &server->adminSession, &methodNodeId,
                    0, UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                    (UA_EditNodeCallback)editMethodCallback,
                    (void*)(uintptr_t)methodCallback);
}

UA_StatusCode
UA_Server_setMethodNodeCallback(UA_Server *server,
                                const UA_NodeId methodNodeId,
                                UA_MethodCallback methodCallback) {
    lockServer(server);
    UA_StatusCode retVal = setMethodNode_callback(server, methodNodeId, methodCallback);
    unlockServer(server);
    return retVal;
}

UA_StatusCode
UA_Server_getMethodNodeCallback(UA_Server *server,
                                const UA_NodeId methodNodeId,
                                UA_MethodCallback *outMethodCallback) {
    lockServer(server);
    const UA_Node *node = UA_NODESTORE_GET(server, &methodNodeId);
    if(!node) {
        unlockServer(server);
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    if(node->head.nodeClass != UA_NODECLASS_METHOD) {
        UA_NODESTORE_RELEASE(server, node);
        unlockServer(server);
        return UA_STATUSCODE_BADNODECLASSINVALID;
    }

    *outMethodCallback = node->methodNode.method;
    UA_NODESTORE_RELEASE(server, node);
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

#endif

/************************/
/* Lifecycle Management */
/************************/

void UA_EXPORT
UA_Server_setAdminSessionContext(UA_Server *server,
                                 void *context) {
    server->adminSession.context = context;
}

static UA_StatusCode
setNodeTypeLifecycleCallback(UA_Server *server, UA_Session *session,
                             UA_Node *node, UA_NodeTypeLifecycle *lifecycle) {
    if(node->head.nodeClass == UA_NODECLASS_OBJECTTYPE) {
        node->objectTypeNode.lifecycle = *lifecycle;
    } else if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) {
        node->variableTypeNode.lifecycle = *lifecycle;
    } else {
        return UA_STATUSCODE_BADNODECLASSINVALID;
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                     UA_NodeTypeLifecycle lifecycle) {
    return editNode(server, &server->adminSession, &nodeId, 0,
                    UA_REFERENCETYPESET_NONE, UA_BROWSEDIRECTION_INVALID,
                    (UA_EditNodeCallback)setNodeTypeLifecycleCallback,
                    &lifecycle);
}

UA_StatusCode
UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                               UA_NodeTypeLifecycle lifecycle) {
    lockServer(server);
    UA_StatusCode retval = setNodeTypeLifecycle(server, nodeId, lifecycle);
    unlockServer(server);
    return retval;
}

/**** amalgamated original file "/deps/libc_time.c" ****/

/* Originally released by the musl project (http://www.musl-libc.org/) under the
 * MIT license. Taken from the file /src/time/__secs_to_tm.c */

#include <limits.h>

/* 2000-03-01 (mod 400 year, immediately after feb29 */
#define LEAPOCH (946684800LL + 86400*(31+29))

#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y   (365*4   + 1)

int
musl_secs_to_tm(long long t, struct musl_tm *tm) {
    long long days, secs, years;
    int remdays, remsecs, remyears;
    int qc_cycles, c_cycles, q_cycles;
    int months;
    int wday, yday, leap;
    static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};

    /* Reject time_t values whose year would overflow int */
    if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
        return -1;

    secs = t - LEAPOCH;
    days = secs / 86400LL;
    remsecs = (int)(secs % 86400);
    if (remsecs < 0) {
        remsecs += 86400;
        --days;
    }

    wday = (int)((3+days)%7);
    if (wday < 0) wday += 7;

    qc_cycles = (int)(days / DAYS_PER_400Y);
    remdays = (int)(days % DAYS_PER_400Y);
    if (remdays < 0) {
        remdays += DAYS_PER_400Y;
        --qc_cycles;
    }

    c_cycles = remdays / DAYS_PER_100Y;
    if (c_cycles == 4) --c_cycles;
    remdays -= c_cycles * DAYS_PER_100Y;

    q_cycles = remdays / DAYS_PER_4Y;
    if (q_cycles == 25) --q_cycles;
    remdays -= q_cycles * DAYS_PER_4Y;

    remyears = remdays / 365;
    if (remyears == 4) --remyears;
    remdays -= remyears * 365;

    leap = !remyears && (q_cycles || !c_cycles);
    yday = remdays + 31 + 28 + leap;
    if (yday >= 365+leap) yday -= 365+leap;

    years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles;

    for (months=0; days_in_month[months] <= remdays; months++)
        remdays -= days_in_month[months];

    if (months >= 10) {
        months -= 12;
        years++;
    }

    if (years+100 > INT_MAX || years+100 < INT_MIN)
        return -1;

    tm->tm_year = (int)(years + 100);
    tm->tm_mon = months + 2;
    tm->tm_mday = remdays + 1;
    tm->tm_wday = wday;
    tm->tm_yday = yday;

    tm->tm_hour = remsecs / 3600;
    tm->tm_min = remsecs / 60 % 60;
    tm->tm_sec = remsecs % 60;

    return 0;
}

static const int secs_through_month[] =
    {0, 31*86400, 59*86400, 90*86400,
     120*86400, 151*86400, 181*86400, 212*86400,
     243*86400, 273*86400, 304*86400, 334*86400 };

static int
musl_month_to_secs(int month, int is_leap) {
    int t = secs_through_month[month];
    if (is_leap && month >= 2)
        t+=86400;
    return t;
}

static long long
musl_year_to_secs(const long long year, int *is_leap) {
    if (year-2ULL <= 136) {
        int y = (int)year;
        int leaps = (y-68)>>2;
        if (!((y-68)&3)) {
            leaps--;
            if (is_leap) *is_leap = 1;
        } else if (is_leap) *is_leap = 0;
        return 31536000*(y-70) + 86400*leaps;
    }

    int cycles, centuries, leaps, rem, dummy;

    if (!is_leap) is_leap = &dummy;
    cycles = (int)((year-100) / 400);
    rem = (int)((year-100) % 400);
    if (rem < 0) {
        cycles--;
        rem += 400;
    }
    if (!rem) {
        *is_leap = 1;
        centuries = 0;
        leaps = 0;
    } else {
        if (rem >= 200) {
            if (rem >= 300) centuries = 3, rem -= 300;
            else centuries = 2, rem -= 200;
        } else {
            if (rem >= 100) centuries = 1, rem -= 100;
            else centuries = 0;
        }
        if (!rem) {
            *is_leap = 0;
            leaps = 0;
        } else {
            leaps = rem / 4;
            rem %= 4;
            *is_leap = !rem;
        }
    }

    leaps += 97*cycles + 24*centuries - *is_leap;

    return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
}

long long
musl_tm_to_secs(const struct musl_tm *tm) {
    int is_leap;
    long long year = tm->tm_year;
    int month = tm->tm_mon;
    if (month >= 12 || month < 0) {
        int adj = month / 12;
        month %= 12;
        if (month < 0) {
            adj--;
            month += 12;
        }
        year += adj;
    }
    long long t = musl_year_to_secs(year, &is_leap);
    t += musl_month_to_secs(month, is_leap);
    t += 86400LL * (tm->tm_mday-1);
    t += 3600LL * tm->tm_hour;
    t += 60LL * tm->tm_min;
    t += tm->tm_sec;
    return t;
}

/**** amalgamated original file "/deps/pcg_basic.c" ****/

/*
 * PCG Random Number Generation for C.
 *
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *       http://www.pcg-random.org
 */


void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq) {
    rng->state = 0U;
    rng->inc = (initseq << 1u) | 1u;
    pcg32_random_r(rng);
    rng->state += initial_state;
    pcg32_random_r(rng);
}

uint32_t pcg32_random_r(pcg32_random_t* rng) {
    uint64_t oldstate = rng->state;
    rng->state = oldstate * 6364136223846793005ULL + rng->inc;
    uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u);
    uint32_t rot = (uint32_t)(oldstate >> 59u);
    return (xorshifted >> rot) | (xorshifted << ((~rot + 1u) & 31)); /* was (xorshifted >> rot) | (xorshifted << ((-rot) & 31)) */
}

/**** amalgamated original file "/deps/base64.c" ****/

/*
 * Base64 encoding/decoding (RFC1341)
 * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
 * Copyright (c) 2025, Julius Pfrommer (Fraunhofer IOSB)
 *
 * This software may be distributed under the terms of the BSD license.
 * See README for more details.
 */


static const unsigned char base64_table[65] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

unsigned char *
UA_base64(const unsigned char *src, size_t len, size_t *out_len) {
    if(len == 0) {
        *out_len = 0;
        return NULL;
    }

    size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */
    if(olen < len)
        return NULL; /* integer overflow */

    unsigned char *out = (unsigned char*)UA_malloc(olen);
    if(!out)
        return NULL;

    *out_len = UA_base64_buf(src, len, out);
    return out;
}

size_t
UA_base64_buf(const unsigned char *src, size_t len, unsigned char *out) {
    const unsigned char *end = src + len;
    const unsigned char *in = src;
    unsigned char *pos = out;
    while(end - in >= 3) {
        *pos++ = base64_table[in[0] >> 2];
        *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
        *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
        *pos++ = base64_table[in[2] & 0x3f];
        in += 3;
    }

    if(end - in) {
        *pos++ = base64_table[in[0] >> 2];
        if(end - in == 1) {
            *pos++ = base64_table[(in[0] & 0x03) << 4];
            *pos++ = '=';
        } else {
            *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
            *pos++ = base64_table[(in[1] & 0x0f) << 2];
        }
        *pos++ = '=';
    }

    return (size_t)(pos - out);
}

static unsigned char dtable[128] = {
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80,
    0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 62  , 0x80, 62  , 0x80, 63  ,
    52  , 53  , 54  , 55  , 56  , 57  , 58  , 59  , 60  , 61  , 0x80, 0x80, 0x80, 0   , 0x80, 0x80,
    0x80, 0   , 1   , 2   , 3   , 4   , 5   , 6   , 7   , 8   , 9   , 10  , 11  , 12  , 13  , 14  ,
    15  , 16  , 17  , 18  , 19  , 20  , 21  , 22  , 23  , 24  , 25  , 0x80, 0x80, 0x80, 0x80, 63  ,
    0x80, 26  , 27  , 28  , 29  , 30  , 31  , 32  , 33  , 34  , 35  , 36  , 37  , 38  , 39  , 40  ,
    41  , 42  , 43  , 44  , 45  , 46  , 47  , 48  , 49  , 50  , 51  , 0x80, 0x80, 0x80, 0x80, 0x80
};

unsigned char *
UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) {
    /* Empty base64 results in an empty byte-string */
    if(len == 0) {
        *out_len = 0;
        return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
    }

    /* Allocate the output string. Append four bytes to allow missing padding */
    size_t olen = (len / 4 * 3) + 4;
    unsigned char *out = (unsigned char*)UA_malloc(olen);
    if(!out)
        return NULL;

    /* Iterate over the input */
    size_t pad = 0;
    unsigned char count = 0;
    unsigned char block[4];
    unsigned char *pos = out;
    for(size_t i = 0; i < len; i++) {
        if(src[i] & 0x80)
            goto error; /* Non-ASCII input */
        unsigned char tmp = dtable[src[i]];
        if(tmp == 0x80)
            goto error; /* Not an allowed character */
        if(tmp == 0x7f)
            continue; /* Whitespace is ignored to accomodate RFC 2045, used in
                       * XML for xs:base64Binary. */
        block[count++] = tmp;

        /* Padding */
        if(src[i] == '=') {
            if(count < 3) /* Padding can only be the last two bytes of a block */
                goto error;
            block[count-1] = 0;
            pad++;
        } else if(pad > 0) {
            goto error; /* Padding not terminated correctly */
        }

        /* Write three output characters for four characters of input */
        if(count == 4) {
            if(pad > 2)
                goto error; /* Invalid padding */
            *pos++ = (block[0] << 2) | (block[1] >> 4);
            *pos++ = (block[1] << 4) | (block[2] >> 2);
            *pos++ = (block[2] << 6) | block[3];
            count = 0;
            pos -= pad;
            pad = 0;
        }
    }

    /* Input length not a multiple of four */
    if(count > 0)
        goto error;

    *out_len = (size_t)(pos - out);
    if(*out_len == 0) {
        UA_free(out);
        return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
    }
    return out;

 error:
    UA_free(out);
    return NULL;
}

/**** amalgamated original file "/deps/dtoa.c" ****/

// Copyright 2013, Andreas Samoljuk
// Copyright 2023, Julius Pfrommer
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#define mantissa_bits 52
#define exponent_bits 11
#define fracmask  0x000FFFFFFFFFFFFFU
#define expmask   0x7FF0000000000000U
#define hiddenbit 0x0010000000000000U
//#define signmask  0x8000000000000000U
#define expbias   (1023 + 52)

#define absv(n) ((n) < 0 ? -(n) : (n))
#define minv(a, b) ((a) < (b) ? (a) : (b))

static uint64_t tens[] = {
    10000000000000000000U, 1000000000000000000U, 100000000000000000U,
    10000000000000000U, 1000000000000000U, 100000000000000U,
    10000000000000U, 1000000000000U, 100000000000U,
    10000000000U, 1000000000U, 100000000U,
    10000000U, 1000000U, 100000U,
    10000U, 1000U, 100U,
    10U, 1U
};

#define npowers     87
#define steppowers  8
#define firstpower -348 /* 10 ^ -348 */
#define expmax     -32
#define expmin     -60

typedef struct Fp {
    uint64_t frac;
    int exp;
} Fp;

static Fp powers_ten[] = {
    { 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
    { 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
    { 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
    { 12353653155963782858U, -1060 }, { 18408377700990114895U, -1034 },
    { 13715310171984221708U, -1007 }, { 10218702384817765436U, -980 },
    { 15227053142812498563U, -954 },  { 11345038669416679861U, -927 },
    { 16905424996341287883U, -901 },  { 12595523146049147757U, -874 },
    { 9384396036005875287U,  -847 },  { 13983839803942852151U, -821 },
    { 10418772551374772303U, -794 },  { 15525180923007089351U, -768 },
    { 11567161174868858868U, -741 },  { 17236413322193710309U, -715 },
    { 12842128665889583758U, -688 },  { 9568131466127621947U,  -661 },
    { 14257626930069360058U, -635 },  { 10622759856335341974U, -608 },
    { 15829145694278690180U, -582 },  { 11793632577567316726U, -555 },
    { 17573882009934360870U, -529 },  { 13093562431584567480U, -502 },
    { 9755464219737475723U,  -475 },  { 14536774485912137811U, -449 },
    { 10830740992659433045U, -422 },  { 16139061738043178685U, -396 },
    { 12024538023802026127U, -369 },  { 17917957937422433684U, -343 },
    { 13349918974505688015U, -316 },  { 9946464728195732843U,  -289 },
    { 14821387422376473014U, -263 },  { 11042794154864902060U, -236 },
    { 16455045573212060422U, -210 },  { 12259964326927110867U, -183 },
    { 18268770466636286478U, -157 },  { 13611294676837538539U, -130 },
    { 10141204801825835212U, -103 },  { 15111572745182864684U, -77 },
    { 11258999068426240000U, -50 },   { 16777216000000000000U, -24 },
    { 12500000000000000000U,   3 },   { 9313225746154785156U,   30 },
    { 13877787807814456755U,  56 },   { 10339757656912845936U,  83 },
    { 15407439555097886824U, 109 },   { 11479437019748901445U, 136 },
    { 17105694144590052135U, 162 },   { 12744735289059618216U, 189 },
    { 9495567745759798747U,  216 },   { 14149498560666738074U, 242 },
    { 10542197943230523224U, 269 },   { 15709099088952724970U, 295 },
    { 11704190886730495818U, 322 },   { 17440603504673385349U, 348 },
    { 12994262207056124023U, 375 },   { 9681479787123295682U,  402 },
    { 14426529090290212157U, 428 },   { 10748601772107342003U, 455 },
    { 16016664761464807395U, 481 },   { 11933345169920330789U, 508 },
    { 17782069995880619868U, 534 },   { 13248674568444952270U, 561 },
    { 9871031767461413346U,  588 },   { 14708983551653345445U, 614 },
    { 10959046745042015199U, 641 },   { 16330252207878254650U, 667 },
    { 12166986024289022870U, 694 },   { 18130221999122236476U, 720 },
    { 13508068024458167312U, 747 },   { 10064294952495520794U, 774 },
    { 14996968138956309548U, 800 },   { 11173611982879273257U, 827 },
    { 16649979327439178909U, 853 },   { 12405201291620119593U, 880 },
    { 9242595204427927429U,  907 },   { 13772540099066387757U, 933 },
    { 10261342003245940623U, 960 },   { 15290591125556738113U, 986 },
    { 11392378155556871081U, 1013 },  { 16975966327722178521U, 1039 },
    { 12648080533535911531U, 1066 }
};

static Fp
find_cachedpow10(int exp, int* k) {
    const double one_log_ten = 0.30102999566398114;
    int approx = (int)(-(exp + npowers) * one_log_ten);
    int idx = (approx - firstpower) / steppowers;
    while(1) {
        int current = exp + powers_ten[idx].exp + 64;
        if(current < expmin) {
            idx++;
            continue;
        }
        if(current > expmax) {
            idx--;
            continue;
        }
        *k = (firstpower + idx * steppowers);
        return powers_ten[idx];
    }
}

static Fp build_fp(uint64_t bits) {
    Fp fp;
    fp.frac = bits & fracmask;
    fp.exp = (bits & expmask) >> 52;
    if(fp.exp) {
        fp.frac += hiddenbit;
        fp.exp -= expbias;
    } else {
        fp.exp = -expbias + 1;
    }
    return fp;
}

static void normalize(Fp* fp) {
    while((fp->frac & hiddenbit) == 0) {
        fp->frac <<= 1;
        fp->exp--;
    }
    int shift = 64 - 52 - 1;
    fp->frac <<= shift;
    fp->exp -= shift;
}

static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper) {
    upper->frac = (fp->frac << 1) + 1;
    upper->exp  = fp->exp - 1;
    while ((upper->frac & (hiddenbit << 1)) == 0) {
        upper->frac <<= 1;
        upper->exp--;
    }

    int u_shift = 64 - 52 - 2;
    upper->frac <<= u_shift;
    upper->exp = upper->exp - u_shift;

    int l_shift = fp->frac == hiddenbit ? 2 : 1;
    lower->frac = (fp->frac << l_shift) - 1;
    lower->exp = fp->exp - l_shift;
    lower->frac <<= lower->exp - upper->exp;
    lower->exp = upper->exp;
}

static Fp multiply(Fp* a, Fp* b) {
    const uint64_t lomask = 0x00000000FFFFFFFF;
    uint64_t ah_bl = (a->frac >> 32)    * (b->frac & lomask);
    uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32);
    uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask);
    uint64_t ah_bh = (a->frac >> 32)    * (b->frac >> 32);
    uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32); 
    /* round up */
    tmp += 1U << 31;
    Fp fp;
    fp.frac = ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32);
    fp.exp = a->exp + b->exp + 64;
    return fp;
}

static void round_digit(char* digits, unsigned ndigits, uint64_t delta,
                        uint64_t rem, uint64_t kappa, uint64_t frac) {
    while(rem < frac && delta - rem >= kappa &&
          (rem + kappa < frac || frac - rem > rem + kappa - frac)) {
        digits[ndigits - 1]--;
        rem += kappa;
    }
}

static unsigned generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) {
    uint64_t wfrac = upper->frac - fp->frac;
    uint64_t delta = upper->frac - lower->frac;

    Fp one;
    one.frac = 1ULL << -upper->exp;
    one.exp  = upper->exp;

    uint64_t part1 = upper->frac >> -one.exp;
    uint64_t part2 = upper->frac & (one.frac - 1);

    unsigned idx = 0;
    int kappa = 10;
    uint64_t* divp;

    /* 1000000000 */
    for(divp = tens + 10; kappa > 0; divp++) {
        uint64_t div = *divp;
        uint64_t digit = part1 / div;
        if(digit || idx) {
            digits[idx++] = (char)(digit + '0');
        }

        part1 -= digit * div;
        kappa--;

        uint64_t tmp = (part1 <<-one.exp) + part2;
        if(tmp <= delta) {
            *K += kappa;
            round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac);
            return idx;
        }
    }

    /* 10 */
    uint64_t* unit = tens + 18;
    while(true) {
        part2 *= 10;
        delta *= 10;
        kappa--;

        uint64_t digit = part2 >> -one.exp;
        if(digit || idx) {
            digits[idx++] = (char)(digit + '0');
        }

        part2 &= one.frac - 1;
        if(part2 < delta) {
            *K += kappa;
            round_digit(digits, idx, delta, part2, one.frac, wfrac * *unit);
            break;
        }
        unit--;
    }
    return idx;
}

static unsigned grisu2(uint64_t bits, char* digits, int* K) {
    Fp w = build_fp(bits);
    Fp lower, upper;
    get_normalized_boundaries(&w, &lower, &upper);
    normalize(&w);
    int k;
    Fp cp = find_cachedpow10(upper.exp, &k);
    w     = multiply(&w,     &cp);
    upper = multiply(&upper, &cp);
    lower = multiply(&lower, &cp);
    lower.frac++;
    upper.frac--;
    *K = -k;
    return generate_digits(&w, &upper, &lower, digits, K);
}

static unsigned
emit_digits(char* digits, unsigned ndigits, char* dest, int K, bool neg) {
    int exp = absv(K + (int)ndigits - 1);

    /* write plain integer */
    if(K >= 0 && (exp < (int)ndigits + 7)) {
        memcpy(dest, digits, ndigits);
        memset(dest + ndigits, '0', (unsigned)K);
        memcpy(dest + ndigits + (unsigned)K, ".0", 2); /* always append .0 for naked integers */
        return (unsigned)(ndigits + (unsigned)K + 2);
    }

    /* write decimal w/o scientific notation */
    if(K < 0 && (K > -7 || exp < 4)) {
        int offset = (int)ndigits - absv(K);
        if(offset <= 0) {
            /* fp < 1.0 -> write leading zero */
            offset = -offset;
            dest[0] = '0';
            dest[1] = '.';
            memset(dest + 2, '0', (size_t)offset);
            memcpy(dest + offset + 2, digits, ndigits);
            return ndigits + 2 + (unsigned)offset;
        } else {
            /* fp > 1.0 */
            memcpy(dest, digits, (size_t)offset);
            dest[offset] = '.';
            memcpy(dest + offset + 1, digits + offset, ndigits - (unsigned)offset);
            return ndigits + 1;
        }
    }

    /* write decimal w/ scientific notation */
    ndigits = minv(ndigits, (unsigned)(18 - neg));
    unsigned idx = 0;
    dest[idx++] = digits[0];
    if(ndigits > 1) {
        dest[idx++] = '.';
        memcpy(dest + idx, digits + 1, ndigits - 1);
        idx += ndigits - 1;
    }

    dest[idx++] = 'e';

    char sign = K + (int)ndigits - 1 < 0 ? '-' : '+';
    dest[idx++] = sign;

    int cent = 0;
    if(exp > 99) {
        cent = exp / 100;
        dest[idx++] = (char)(cent + '0');
        exp -= cent * 100;
    }
    if(exp > 9) {
        int dec = exp / 10;
        dest[idx++] = (char)(dec + '0');
        exp -= dec * 10;

    } else if(cent) {
        dest[idx++] = '0';
    }
    dest[idx++] = (char)(exp % 10 + '0');
    return idx;
}

unsigned dtoa(double d, char* buffer) {
    uint64_t bits = 0;
    memcpy(&bits, &d, sizeof(double));

    uint64_t mantissa = bits & ((1ull << mantissa_bits) - 1);
    uint32_t exponent = (uint32_t)
        ((bits >> mantissa_bits) & ((1u << exponent_bits) - 1));

    if(exponent == 0 && mantissa == 0) {
        memcpy(buffer, "0.0", 3);
        return 3;
    }

    bool sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
    unsigned pos = 0;
    if(sign) {
        buffer[0] = '-';
        pos++;
    }

    if(exponent == ((1u << exponent_bits) - 1u)) {
        if(mantissa != 0) {
            memcpy(buffer, "nan", 3);
            return 3;
        } else {
            memcpy(&buffer[pos], "inf", 3);
            return pos + 3;
        }
    }

    int K = 0;
    char digits[18];
    memset(digits, 0, 18);
    unsigned ndigits = grisu2(bits, digits, &K);
    return pos + emit_digits(digits, ndigits, &buffer[pos], K, sign);
}

/**** amalgamated original file "/deps/musl_inet_pton.c" ****/

/* musl as a whole is licensed under the following standard MIT license:
 *
 * ----------------------------------------------------------------------
 * Copyright © 2005-2020 Rich Felker, et al.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *----------------------------------------------------------------------
 */

#include <ctype.h>
#include <errno.h>
#include <string.h>

static int hexval(unsigned c)
{
	if (c-'0'<10) return (int)(c-'0');
	c |= 32;
	if (c-'a'<6) return (int)(c-'a'+10);
	return -1;
}

int musl_inet_pton(int af, const char * UA_RESTRICT s, void * UA_RESTRICT a0)
{
	uint16_t ip[8];
	unsigned char *a = (unsigned char *)a0;
	int i, j, v, d, brk=-1, need_v4=0;

	if (af==AF_INET) {
		for (i=0; i<4; i++) {
			for (v=j=0; j<3 && isdigit((unsigned char)s[j]); j++)
				v = 10*v + s[j]-'0';
			if (j==0 || (j>1 && s[0]=='0') || v>255) return 0;
			a[i] = (unsigned char)v;
			if (s[j]==0 && i==3) return 1;
			if (s[j]!='.') return 0;
			s += j+1;
		}
		return 0;
	} else if (af!=AF_INET6) {
		errno = EAFNOSUPPORT;
		return -1;
	}

	if (*s==':' && *++s!=':') return 0;

	for (i=0; ; i++) {
		if (s[0]==':' && brk<0) {
			brk=i;
			ip[i&7]=0;
			if (!*++s) break;
			if (i==7) return 0;
			continue;
		}
		for (v=j=0; j<4 && (d=hexval((unsigned)s[j]))>=0; j++)
			v=16*v+d;
		if (j==0) return 0;
		ip[i&7] = (uint16_t)v;
		if (!s[j] && (brk>=0 || i==7)) break;
		if (i==7) return 0;
		if (s[j]!=':') {
			if (s[j]!='.' || (i<6 && brk<0)) return 0;
			need_v4=1;
			i++;
			ip[i&7]=0;
			break;
		}
		s += j+1;
	}
	if (brk>=0) {
		memmove(ip+brk+7-i, ip+brk, (size_t)(2*(i+1-brk)));
		for (j=0; j<7-i; j++) ip[brk+j] = 0;
	}
	for (j=0; j<8; j++) {
		*a++ = (unsigned char)(ip[j]>>8);
		*a++ = (unsigned char)ip[j];
	}
	if (need_v4 && musl_inet_pton(AF_INET, (char *)(uintptr_t)s, a-4) <= 0) return 0;
	return 1;
}

/**** amalgamated original file "/deps/mp_printf.c" ****/

/**
 * @author (c) Julius Pfrommer
 *             2023, Fraunhofer IOSB, Germany
 * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
 *             2021-2023, Haifa, Palestine/Israel
 * @author (c) Marco Paland (info@paland.com)
 *             2014-2019, PALANDesign Hannover, Germany
 *
 * @note Others have made smaller contributions to this file: see the
 * contributors page at https://github.com/eyalroz/printf/graphs/contributors
 * or ask one of the authors. The original code for exponential specifiers was
 * contributed by Martijn Jasperse <m.jasperse@gmail.com>.
 *
 * @brief Small stand-alone implementation of the printf family of functions
 * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
 * limited resources.
 *
 * @note the implementations are thread-safe; re-entrant; use no functions from
 * the standard library; and do not dynamically allocate any memory.
 *
 * @license The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */



#include <stdint.h>
#include <stdbool.h>

// 'ntoa' conversion buffer size, this must be big enough to hold one converted
// numeric number including padded zeros (dynamically created on stack)
#define PRINTF_INTEGER_BUFFER_SIZE    32

// size of the fixed (on-stack) buffer for printing individual decimal numbers.
// this must be big enough to hold one converted floating-point value including
// padded zeros.
#define PRINTF_DECIMAL_BUFFER_SIZE    32

// Default precision for the floating point conversion specifiers (the C
// standard sets this at 6)
#define PRINTF_DEFAULT_FLOAT_PRECISION  6

// internal flag definitions
#define FLAGS_ZEROPAD   (1U <<  0U)
#define FLAGS_LEFT      (1U <<  1U)
#define FLAGS_PLUS      (1U <<  2U)
#define FLAGS_SPACE     (1U <<  3U)
#define FLAGS_HASH      (1U <<  4U)
#define FLAGS_UPPERCASE (1U <<  5U)
#define FLAGS_CHAR      (1U <<  6U)
#define FLAGS_SHORT     (1U <<  7U)
  // Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
#define FLAGS_LONG      (1U <<  9U)
#define FLAGS_LONG_LONG (1U << 10U)
#define FLAGS_PRECISION (1U << 11U)
#define FLAGS_ADAPT_EXP (1U << 12U)
#define FLAGS_POINTER   (1U << 13U)
  // Note: Similar, but not identical, effect as FLAGS_HASH
#define FLAGS_SIGNED    (1U << 14U)

#define BASE_BINARY    2
#define BASE_OCTAL     8
#define BASE_DECIMAL  10
#define BASE_HEX      16

typedef unsigned int printf_flags_t;
typedef uint8_t numeric_base_t;
typedef unsigned long long printf_unsigned_value_t;
typedef long long printf_signed_value_t;

// Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid
// and well-defined, but if you're not careful you can easily trigger undefined
// behavior with -LONG_MIN or -LLONG_MIN
#define ABS_FOR_PRINTING(_x)                                            \
    ((printf_unsigned_value_t)((_x) > 0 ? (_x) : -((printf_signed_value_t)_x)))

// internal secure strlen @return The length of the string (excluding the
// terminating 0) limited by 'maxsize' @note strlen uses size_t, but wes only
// use this function with size_t variables - hence the signature.
static size_t
strnlen_s_(const char *str, size_t maxsize) {
    for(size_t i = 0; i < maxsize; i++) {
        if(!str[i])
            return i;
    }
    return maxsize;
}

// internal test if char is a digit (0-9)
// @return true if char is a digit
static bool is_digit_(char ch) { return (ch >= '0') && (ch <= '9'); }

// internal ASCII string to size_t conversion
static size_t
atou_(const char **str) {
    size_t i = 0U;
    while(is_digit_(**str)) {
        i = i * 10U + (size_t)(*((*str)++) - '0');
    }
    return i;
}

// Output buffer
typedef struct {
    char *buffer;
    size_t pos;
    size_t max_chars;
} output_t;

static void
putchar_(output_t *out, char c) {
    size_t write_pos = out->pos++;
    // We're _always_ increasing pos, so as to count how may characters
    // _would_ have been written if not for the max_chars limitation
    if(write_pos >= out->max_chars)
        return;
    // it must be the case that out->buffer != NULL , due to the constraint
    // on output_t ; and note we're relying on write_pos being non-negative.
    out->buffer[write_pos] = c;
}

static void
out_(output_t *out, const char *buf, size_t len) {
    if(out->pos < out->max_chars) {
        size_t write_len = len;
        if(out->pos + len > out->max_chars)
            write_len = out->max_chars - out->pos;
        for(size_t i = 0; i < write_len; i++)
            out->buffer[out->pos + i] = buf[i];
    }
    out->pos += len; // Always increase pos by len
}

// output the specified string in reverse, taking care of any zero-padding
static void
out_rev_(output_t *output, const char *buf, size_t len, size_t width,
         printf_flags_t flags) {
    const size_t start_pos = output->pos;

    // pad spaces up to given width
    if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
        for(size_t i = len; i < width; i++) {
            putchar_(output, ' ');
        }
    }

    // reverse string
    while(len) {
        putchar_(output, buf[--len]);
    }

    // append pad spaces up to given width
    if(flags & FLAGS_LEFT) {
        while(output->pos - start_pos < width) {
            putchar_(output, ' ');
        }
    }
}

// Invoked by print_integer after the actual number has been printed, performing
// necessary work on the number's prefix (as the number is initially printed in
// reverse order)
static void
print_integer_finalization(output_t *output, char *buf, size_t len, bool negative,
                           numeric_base_t base, size_t precision, size_t width,
                           printf_flags_t flags) {
    size_t unpadded_len = len;

    // pad with leading zeros
    if(!(flags & FLAGS_LEFT)) {
        if(width && (flags & FLAGS_ZEROPAD) &&
           (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
            width--;
        }
        while((flags & FLAGS_ZEROPAD) && (len < width) &&
              (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = '0';
        }
    }

    while((len < precision) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
        buf[len++] = '0';
    }

    if(base == BASE_OCTAL && (len > unpadded_len)) {
        // Since we've written some zeros, we've satisfied the alternative format
        // leading space requirement
        flags &= ~FLAGS_HASH;
    }

    // handle hash
    if(flags & (FLAGS_HASH | FLAGS_POINTER)) {
        if(!(flags & FLAGS_PRECISION) && len && ((len == precision) || (len == width))) {
            // Let's take back some padding digits to fit in what will eventually be
            // the format-specific prefix
            if(unpadded_len < len) {
                len--;  // This should suffice for BASE_OCTAL
            }
            if(len && (base == BASE_HEX || base == BASE_BINARY) && (unpadded_len < len)) {
                len--;  // ... and an extra one for 0x or 0b
            }
        }
        if((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) &&
           (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = 'x';
        } else if((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) &&
                  (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = 'X';
        } else if((base == BASE_BINARY) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = 'b';
        }
        if(len < PRINTF_INTEGER_BUFFER_SIZE) {
            buf[len++] = '0';
        }
    }

    if(len < PRINTF_INTEGER_BUFFER_SIZE) {
        if(negative) {
            buf[len++] = '-';
        } else if(flags & FLAGS_PLUS) {
            buf[len++] = '+';  // ignore the space if the '+' exists
        } else if(flags & FLAGS_SPACE) {
            buf[len++] = ' ';
        }
    }

    out_rev_(output, buf, len, width, flags);
}

// An internal itoa-like function
static void
print_integer(output_t *output, printf_unsigned_value_t value, bool negative,
              numeric_base_t base, size_t precision, size_t width, printf_flags_t flags) {
    char buf[PRINTF_INTEGER_BUFFER_SIZE];
    size_t len = 0U;

    if(!value) {
        if(!(flags & FLAGS_PRECISION)) {
            buf[len++] = '0';
            flags &= ~FLAGS_HASH;
            // We drop this flag this since either the alternative and regular modes
            // of the specifier don't differ on 0 values, or (in the case of octal)
            // we've already provided the special handling for this mode.
        } else if(base == BASE_HEX) {
            flags &= ~FLAGS_HASH;
            // We drop this flag this since either the alternative and regular modes
            // of the specifier don't differ on 0 values
        }
    } else {
        do {
            const char digit = (char)(value % base);
            buf[len++] =
                (char)(digit < 10 ? '0' + digit
                                  : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10);
            value /= base;
        } while(value && (len < PRINTF_INTEGER_BUFFER_SIZE));
    }

    print_integer_finalization(output, buf, len, negative, base, precision, width, flags);
}

static void
print_floating_point(output_t *output, double value, size_t precision,
                     size_t width, printf_flags_t flags) {
    if((flags & FLAGS_PLUS) && value > 0.0)
        putchar_(output, '+');

    // set default precision, if not set explicitly
    //if(!(flags & FLAGS_PRECISION) || precision > PRINTF_DECIMAL_BUFFER_SIZE - 5)
    //    precision = PRINTF_DEFAULT_FLOAT_PRECISION;

    char buf[PRINTF_DECIMAL_BUFFER_SIZE];
    unsigned len = dtoa(value, buf); // Fill the buffer (TODO: Consider precision)
    out_(output, buf, len); // Print the buffer
}

// Advances the format pointer past the flags, and returns the parsed flags
// due to the characters passed
static printf_flags_t
parse_flags(const char **format) {
    printf_flags_t flags = 0U;
    do {
        switch(**format) {
        case '0': flags |= FLAGS_ZEROPAD; break;
        case '-': flags |= FLAGS_LEFT; break;
        case '+': flags |= FLAGS_PLUS; break;
        case ' ': flags |= FLAGS_SPACE; break;
        case '#': flags |= FLAGS_HASH; break;
        default: return flags;
        }
        (*format)++;
    } while(true);
}

#define ADVANCE_IN_FORMAT_STRING(cptr_)                                 \
    do {                                                                \
        (cptr_)++;                                                      \
        if(!*(cptr_))                                                   \
            return;                                                     \
    } while(0)

static void
format_string_loop(output_t *output, const char *format, va_list args) {
    while(*format) {
        if(*format != '%') {
            // A regular content character
            putchar_(output, *format);
            format++;
            continue;
        }
        // We're parsing a format specifier: %[flags][width][.precision][length]
        ADVANCE_IN_FORMAT_STRING(format);

        printf_flags_t flags = parse_flags(&format);

        // evaluate width field
        size_t width = 0U;
        if(is_digit_(*format)) {
            width = atou_(&format);
        } else if(*format == '*') {
            const int w = va_arg(args, int);
            if(w < 0) {
                flags |= FLAGS_LEFT;  // reverse padding
                width = (size_t)-w;
            } else {
                width = (size_t)w;
            }
            ADVANCE_IN_FORMAT_STRING(format);
        }

        // evaluate precision field
        size_t precision = 0U;
        if(*format == '.') {
            flags |= FLAGS_PRECISION;
            ADVANCE_IN_FORMAT_STRING(format);
            if(is_digit_(*format)) {
                precision = atou_(&format);
            } else if(*format == '*') {
                const int precision_ = va_arg(args, int);
                precision = precision_ > 0 ? (size_t)precision_ : 0U;
                ADVANCE_IN_FORMAT_STRING(format);
            }
        }

        // evaluate length field
        switch(*format) {
            case 'l':
                flags |= FLAGS_LONG;
                ADVANCE_IN_FORMAT_STRING(format);
                if(*format == 'l') {
                    flags |= FLAGS_LONG_LONG;
                    ADVANCE_IN_FORMAT_STRING(format);
                }
                break;
            case 'h':
                flags |= FLAGS_SHORT;
                ADVANCE_IN_FORMAT_STRING(format);
                if(*format == 'h') {
                    flags |= FLAGS_CHAR;
                    ADVANCE_IN_FORMAT_STRING(format);
                }
                break;
            case 't':
                flags |=
                    (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
                ADVANCE_IN_FORMAT_STRING(format);
                break;
            case 'j':
                flags |=
                    (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
                ADVANCE_IN_FORMAT_STRING(format);
                break;
            case 'z':
                flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
                ADVANCE_IN_FORMAT_STRING(format);
                break;
            default:
                break;
        }

        // evaluate specifier
        switch(*format) {
            case 'd':
            case 'i':
            case 'u':
            case 'x':
            case 'X':
            case 'o':
            case 'b': {
                if(*format == 'd' || *format == 'i') {
                    flags |= FLAGS_SIGNED;
                }

                numeric_base_t base;
                if(*format == 'x' || *format == 'X') {
                    base = BASE_HEX;
                } else if(*format == 'o') {
                    base = BASE_OCTAL;
                } else if(*format == 'b') {
                    base = BASE_BINARY;
                } else {
                    base = BASE_DECIMAL;
                    flags &=
                        ~FLAGS_HASH;  // decimal integers have no alternative presentation
                }

                if(*format == 'X') {
                    flags |= FLAGS_UPPERCASE;
                }

                format++;
                // ignore '0' flag when precision is given
                if(flags & FLAGS_PRECISION) {
                    flags &= ~FLAGS_ZEROPAD;
                }

                if(flags & FLAGS_SIGNED) {
                    // A signed specifier: d, i or possibly I + bit size if enabled
                    if(flags & FLAGS_LONG_LONG) {
                        const long long value = va_arg(args, long long);
                        print_integer(output, ABS_FOR_PRINTING(value), value < 0, base,
                                      precision, width, flags);
                    } else if(flags & FLAGS_LONG) {
                        const long value = va_arg(args, long);
                        print_integer(output, ABS_FOR_PRINTING(value), value < 0, base,
                                      precision, width, flags);
                    } else {
                        // We never try to interpret the argument as something
                        // potentially-smaller than int, due to integer promotion rules:
                        // Even if the user passed a short int, short unsigned etc. -
                        // these will come in after promotion, as int's (or unsigned for
                        // the case of short unsigned when it has the same size as int)
                        const int value =
                            (flags & FLAGS_CHAR)    ? (signed char)va_arg(args, int)
                            : (flags & FLAGS_SHORT) ? (short int)va_arg(args, int)
                                                    : va_arg(args, int);
                        print_integer(output, ABS_FOR_PRINTING(value), value < 0, base,
                                      precision, width, flags);
                    }
                } else {
                    // An unsigned specifier: u, x, X, o, b
                    flags &= ~(FLAGS_PLUS | FLAGS_SPACE);

                    if(flags & FLAGS_LONG_LONG) {
                        print_integer(output, (printf_unsigned_value_t)
                                      va_arg(args, unsigned long long),
                                      false, base, precision, width, flags);
                    } else if(flags & FLAGS_LONG) {
                        print_integer(output, (printf_unsigned_value_t)
                                      va_arg(args, unsigned long),
                                      false, base, precision, width, flags);
                    } else {
                        const unsigned int value = (flags & FLAGS_CHAR)
                            ? (unsigned char)va_arg(args, unsigned int)
                            : (flags & FLAGS_SHORT)
                            ? (unsigned short int)va_arg(args, unsigned int)
                            : va_arg(args, unsigned int);
                        print_integer(output, (printf_unsigned_value_t)value, false, base,
                                      precision, width, flags);
                    }
                }
                break;
            }

            case 'f':
            case 'F':
                if(*format == 'F')
                    flags |= FLAGS_UPPERCASE;
                print_floating_point(output, (double)va_arg(args, double),
                                     precision, width, flags);
                format++;
                break;

            case 'c': {
                size_t l = 1U;
                // pre padding
                if(!(flags & FLAGS_LEFT)) {
                    while(l++ < width) {
                        putchar_(output, ' ');
                    }
                }
                // char output
                putchar_(output, (char)va_arg(args, int));
                // post padding
                if(flags & FLAGS_LEFT) {
                    while(l++ < width) {
                        putchar_(output, ' ');
                    }
                }
                format++;
                break;
            }

            case 's': {
                const char *p = va_arg(args, char *);
                if(p == NULL) {
                    out_rev_(output, ")llun(", 6, width, flags);
                } else {
                    // string length
                    size_t l = strnlen_s_(p, precision ? precision : INT32_MAX);
                    if(flags & FLAGS_PRECISION) {
                        l = (l < precision ? l : precision);
                    }

                    // pre padding
                    if(!(flags & FLAGS_LEFT)) {
                        for(size_t i = 0; l + i < width; i++) {
                            putchar_(output, ' ');
                        }
                    }

                    // string output
                    out_(output, p, l);

                    // post padding
                    if(flags & FLAGS_LEFT) {
                        for(size_t i = 0; l + i < width; i++) {
                            putchar_(output, ' ');
                        }
                    }
                }
                format++;
                break;
            }

            case 'p': {
                width = sizeof(void *) * 2U + 2;  // 2 hex chars per byte + the "0x" prefix
                flags |= FLAGS_ZEROPAD | FLAGS_POINTER;
                uintptr_t value = (uintptr_t)va_arg(args, void *);
                (value == (uintptr_t)NULL)
                    ? out_rev_(output, ")lin(", 5, width, flags)
                    : print_integer(output, (printf_unsigned_value_t)value, false,
                                    BASE_HEX, precision, width, flags);
                format++;
                break;
            }

            case '%':
                putchar_(output, '%');
                format++;
                break;

            case 'S': {
                UA_String s = va_arg(args, UA_String);
                out_(output, (const char*)s.data, s.length);
                format++;
                break;
            }

            case 'N': {
                UA_String buf = UA_STRING_NULL;
                UA_NodeId id = va_arg(args, UA_NodeId);
                UA_StatusCode res = UA_NodeId_print(&id, &buf);
                if(res == UA_STATUSCODE_GOOD) {
                    out_(output, (const char*)buf.data, buf.length);
                    UA_String_clear(&buf);
                } else {
                    out_rev_(output, ")rre(", 5, width, flags);
                }
                format++;
                break;
            }

            case 'Q': {
                UA_String buf = UA_STRING_NULL;
                UA_QualifiedName qn = va_arg(args, UA_QualifiedName);
                UA_StatusCode res = UA_QualifiedName_print(&qn, &buf);
                if(res == UA_STATUSCODE_GOOD) {
                    out_(output, (const char*)buf.data, buf.length);
                    UA_String_clear(&buf);
                } else {
                    out_rev_(output, ")rre(", 5, width, flags);
                }
                format++;
                break;
            }

            default:
                putchar_(output, *format);
                format++;
                break;
        }
    }
}

int
mp_vsnprintf(char *s, size_t n, const char *format, va_list arg) {
    // Format the string
    output_t out = {s, 0, n};
    format_string_loop(&out, format, arg);

    // Write the string-terminating '\0' character
    if(n > 1) {
        size_t null_char_pos = out.pos < n ? out.pos : n - 1;
        out.buffer[null_char_pos] = '\0';
    }

    // Return written chars without terminating \0
    return (int)out.pos;
}

int
mp_snprintf(char *s, size_t n, const char *format, ...) {
    va_list args;
    va_start(args, format);
    const int ret = mp_vsnprintf(s, n, format, args);
    va_end(args);
    return ret;
}

/**** amalgamated original file "/deps/utf8.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#define UTF_PARSE_BYTE(pos) do {                        \
        byte = str[pos];                                \
        if(UTF_UNLIKELY(byte < 0x80 || byte > 0xBF))    \
            return 0; /* Not a continuation byte */     \
        *codepoint = (*codepoint << 6) + (byte & 0x3F); \
    } while(0)

unsigned
utf8_to_codepoint(const unsigned char *str, size_t len, unsigned *codepoint) {
    /* Ensure there is a character to read */
    if(UTF_UNLIKELY(len == 0))
        return 0;

    *codepoint = str[0];
    if(UTF_LIKELY(*codepoint < 0x80))
        return 1; /* Normal ASCII */

    if(UTF_UNLIKELY(*codepoint <= 0xC1))
        return 0; /* Continuation byte not allowed here */

    unsigned count;
    unsigned char byte;
    if(*codepoint <= 0xDF) { /* 2-byte sequence */
        if(len < 2)
            return 0;
        count = 2;
        *codepoint &= 0x1F;
        UTF_PARSE_BYTE(1);
        if(UTF_UNLIKELY(*codepoint < 0x80))
            return 0; /* Too small for the encoding length */
    } else if(*codepoint <= 0xEF) { /* 3-byte sequence */
        if(len < 3)
            return 0;
        count = 3;
        *codepoint &= 0xF;
        UTF_PARSE_BYTE(1);
        UTF_PARSE_BYTE(2);
        if(UTF_UNLIKELY(*codepoint < 0x800))
            return 0; /* Too small for the encoding length */
    } else if(*codepoint <= 0xF4) { /* 4-byte sequence */
        if(len < 4)
            return 0;
        count = 4;
        *codepoint &= 0x7;
        UTF_PARSE_BYTE(1);
        UTF_PARSE_BYTE(2);
        UTF_PARSE_BYTE(3);
        if(UTF_UNLIKELY(*codepoint < 0x10000))
            return 0; /* Too small for the encoding length */
    } else {
        return 0; /* Invalid utf8 encoding */
    }

    if(UTF_UNLIKELY(*codepoint > 0x10FFFF))
        return 0; /* Not in the Unicode range */

    return count;
}

/**** amalgamated original file "/deps/itoa.c" ****/

/*
 * Copyright 2017 Techie Delight
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Originally released by techiedelight.com 
 * (http://www.techiedelight.com/implement-itoa-function-in-c/) under the
 * MIT license. */


static void swap(char *x, char *y) {
    char t = *x;
    *x = *y;
    *y = t;
}

/* function to reverse buffer */
static char* reverse(char *buffer, UA_UInt16 i, UA_UInt16 j) {
    while (i < j)
        swap(&buffer[i++], &buffer[j--]);

    return buffer;
}

/* adapted from http://www.techiedelight.com/implement-itoa-function-in-c/ to use UA_... types */
UA_UInt16 itoaUnsigned(UA_UInt64 value, char* buffer, UA_Byte base) {
    /* consider absolute value of number */
    UA_UInt64 n = value;

    UA_UInt16 i = 0;
    while (n) {
        UA_UInt64 r = n % base;

        if (r >= 10)
            buffer[i++] = (char)(65 + (r - 10));
        else
            buffer[i++] = (char)(48 + r);

        n = n / base;
    }
    /* if number is 0 */
    if (i == 0)
        buffer[i++] = '0';

    buffer[i] = '\0'; /* null terminate string */
    i--;
    /* reverse the string */
    reverse(buffer, 0, i);
    i++;
    return i;
}

/* adapted from http://www.techiedelight.com/implement-itoa-function-in-c/ */
UA_UInt16 itoaSigned(UA_Int64 value, char* buffer) {
    /* Special case for UA_INT64_MIN which can not simply be negated */
    /* it will cause a signed integer overflow */
    UA_UInt64 n;
    if(value == UA_INT64_MIN) {
        n = (UA_UInt64)UA_INT64_MAX + 1;
    } else {
        n = (UA_UInt64)value;
        if(value < 0){
            n = (UA_UInt64)-value;
        }
    }

    UA_UInt16 i = 0;
    while(n) {
        UA_UInt64 r = n % 10;
        buffer[i++] = (char)('0' + r);
        n = n / 10;
    }

    if(i == 0)
        buffer[i++] = '0'; /* if number is 0 */
    if(value < 0)
        buffer[i++] = '-';
    buffer[i] = '\0'; /* null terminate string */
    i--;
    reverse(buffer, 0, i); /* reverse the string and return it */
    i++;
    return i;
}


/**** amalgamated original file "/deps/ziptree.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 *
 *    Copyright 2021-2022 (c) Julius Pfrommer
 */


/* Dummy types */
struct zip_elem;
typedef struct zip_elem zip_elem;
typedef ZIP_ENTRY(zip_elem) zip_entry;
typedef ZIP_HEAD(, zip_elem) zip_head;

/* Access macros */
#define ZIP_ENTRY_PTR(x) ((zip_entry*)((char*)x + fieldoffset))
#define ZIP_KEY_PTR(x) (const void*)((const char*)x + keyoffset)

/* Hash pointers to keep the tie-breeaking of equal keys (mostly) uncorrelated
 * from the rank (pointer order). Hashing code taken from sdbm-hash
 * (http://www.cse.yorku.ca/~oz/hash.html). */
static unsigned int
__ZIP_PTR_HASH(const void *p) {
    unsigned int h = 0;
    const unsigned char *data = (const unsigned char*)&p;
    for(size_t i = 0; i < (sizeof(void*) / sizeof(char)); i++)
        h = data[i] + (h << 6) + (h << 16) - h;
    return h;
}

static ZIP_INLINE enum ZIP_CMP
__ZIP_RANK_CMP(const void *p1, const void *p2) {
    /* assert(p1 != p2); */
    unsigned int h1 = __ZIP_PTR_HASH(p1);
    unsigned int h2 = __ZIP_PTR_HASH(p2);
    if(h1 == h2)
        return (p1 < p2) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    return (h1 < h2) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

static ZIP_INLINE enum ZIP_CMP
__ZIP_UNIQUE_CMP(zip_cmp_cb cmp, const void *p1, const void *p2) {
    if(p1 == p2)
        return ZIP_CMP_EQ;
    enum ZIP_CMP order = cmp(p1, p2);
    if(order == ZIP_CMP_EQ)
        return (p1 < p2) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    return order;
}

#if 0
#include <assert.h>
ZIP_UNUSED static ZIP_INLINE void
__ZIP_VALIDATE(zip_cmp_cb cmp, unsigned short fieldoffset,
               unsigned short keyoffset, void *elm,
               void *min_elm, void *max_elm) {
    if(!elm)
        return;
    enum ZIP_CMP c1 = __ZIP_UNIQUE_CMP(cmp, ZIP_KEY_PTR(min_elm), ZIP_KEY_PTR(elm));
    assert((elm == min_elm && c1 == ZIP_CMP_EQ) || c1 == ZIP_CMP_LESS);

    enum ZIP_CMP c2 = __ZIP_UNIQUE_CMP(cmp, ZIP_KEY_PTR(max_elm), ZIP_KEY_PTR(elm));
    assert((elm == max_elm && c2 == ZIP_CMP_EQ) || c2 == ZIP_CMP_MORE);

    assert(!ZIP_ENTRY_PTR(elm)->right ||
           __ZIP_RANK_CMP(elm, ZIP_ENTRY_PTR(elm)->right) == ZIP_CMP_MORE);
    assert(!ZIP_ENTRY_PTR(elm)->left ||
           __ZIP_RANK_CMP(elm, ZIP_ENTRY_PTR(elm)->left) == ZIP_CMP_MORE);

    __ZIP_VALIDATE(cmp, fieldoffset, keyoffset, ZIP_ENTRY_PTR(elm)->right, elm, max_elm);
    __ZIP_VALIDATE(cmp, fieldoffset, keyoffset, ZIP_ENTRY_PTR(elm)->left, min_elm, elm);
}
#endif

/* Walk down the right-side spine of cur. Elements that are larger than x_key
 * are moved under x->right. */
static void
__ZIP_INSERT_MOVE_RIGHT(zip_cmp_cb cmp, unsigned short fieldoffset,
                        unsigned short keyoffset, const void *x_key,
                        zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->right) {
        zip_elem *move_candidate = ZIP_ENTRY_PTR(cur)->right;
        if(__ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(move_candidate)) == ZIP_CMP_MORE) {
            cur = ZIP_ENTRY_PTR(cur)->right;
            continue;
        }
        ZIP_ENTRY_PTR(cur)->right = ZIP_ENTRY_PTR(move_candidate)->left;
        ZIP_ENTRY_PTR(move_candidate)->left = NULL;
        *fix_edge = move_candidate;
        fix_edge = &ZIP_ENTRY_PTR(move_candidate)->left;
    }
}

static void
__ZIP_INSERT_MOVE_LEFT(zip_cmp_cb cmp, unsigned short fieldoffset,
                       unsigned short keyoffset, const void *x_key,
                       zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->left) {
        zip_elem *move_candidate = ZIP_ENTRY_PTR(cur)->left;
        if(__ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(move_candidate)) == ZIP_CMP_LESS) {
            cur = ZIP_ENTRY_PTR(cur)->left;
            continue;
        }
        ZIP_ENTRY_PTR(cur)->left = ZIP_ENTRY_PTR(move_candidate)->right;
        ZIP_ENTRY_PTR(move_candidate)->right = NULL;
        *fix_edge = move_candidate;
        fix_edge = &ZIP_ENTRY_PTR(move_candidate)->right;
    }
}

void
__ZIP_INSERT(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm) {
    zip_elem *x = (zip_elem*)elm;
    ZIP_ENTRY_PTR(x)->left = NULL;
    ZIP_ENTRY_PTR(x)->right = NULL;

    const void *x_key = ZIP_KEY_PTR(x);
    zip_head *head = (zip_head*)h;
    if(!head->root) {
        head->root = x;
        return;
    }

    /* Go down the tree to find the top element "cur" that has a rank smaller
     * than "x" */
    zip_elem *prev = NULL;
    zip_elem *cur = head->root;
    enum ZIP_CMP cur_order, prev_order = ZIP_CMP_EQ;
    do {
        cur_order = __ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(cur));
        if(cur_order == ZIP_CMP_EQ)
            return; /* x is already inserted */
        if(__ZIP_RANK_CMP(cur, x) == ZIP_CMP_LESS)
            break;
        prev = cur;
        prev_order = cur_order;
        cur = (cur_order == ZIP_CMP_MORE) ?
            ZIP_ENTRY_PTR(cur)->right : ZIP_ENTRY_PTR(cur)->left;
    } while(cur);

    /* Insert "x" instead of "cur" under its parent "prev" */
    if(cur == head->root) {
        head->root = x;
    } else {
        if(prev_order == ZIP_CMP_MORE)
            ZIP_ENTRY_PTR(prev)->right = x;
        else
            ZIP_ENTRY_PTR(prev)->left = x;
    }

    if(!cur)
        return;

    /* Re-insert "cur" under "x". Repair by moving elements that ended up on the
     * wrong side of "x". */
    if(cur_order == ZIP_CMP_MORE) {
        ZIP_ENTRY_PTR(x)->left = cur;
        __ZIP_INSERT_MOVE_RIGHT(cmp, fieldoffset, keyoffset,
                                x_key, &ZIP_ENTRY_PTR(x)->right, cur);
    } else {
        ZIP_ENTRY_PTR(x)->right = cur;
        __ZIP_INSERT_MOVE_LEFT(cmp, fieldoffset, keyoffset,
                               x_key, &ZIP_ENTRY_PTR(x)->left, cur);
    }
}

void *
__ZIP_REMOVE(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm) {
    zip_head *head = (zip_head*)h;
    zip_elem *x = (zip_elem*)elm;
    zip_elem *cur = head->root;
    if(!cur)
        return NULL;

    const void *x_key = ZIP_KEY_PTR(x);
    zip_elem **prev_edge = &head->root;
    enum ZIP_CMP cur_order = __ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(cur));
    while(cur_order != ZIP_CMP_EQ) {
        prev_edge = (cur_order == ZIP_CMP_LESS) ?
            &ZIP_ENTRY_PTR(cur)->left : &ZIP_ENTRY_PTR(cur)->right;
        cur = *prev_edge;
        if(!cur)
            return NULL;
        cur_order = __ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(cur));
    }
    *prev_edge = (zip_elem*)__ZIP_ZIP(fieldoffset,
                                      ZIP_ENTRY_PTR(cur)->left,
                                      ZIP_ENTRY_PTR(cur)->right);
    return cur;
}

void *
__ZIP_ITER(unsigned short fieldoffset, zip_iter_cb cb,
           void *context, void *elm) {
    if(!elm)
        return NULL;
    zip_elem *left = ZIP_ENTRY_PTR(elm)->left;
    zip_elem *right = ZIP_ENTRY_PTR(elm)->right;
    void *res = __ZIP_ITER(fieldoffset, cb, context, left);
    if(res)
        return res;
    res = cb(context, elm);
    if(res)
        return res;
    return __ZIP_ITER(fieldoffset, cb, context, right);
}

void *
__ZIP_ITER_KEY(zip_cmp_cb cmp, unsigned short fieldoffset,
               unsigned short keyoffset, const void *key,
               zip_iter_cb cb, void *context, void *elm) {
    if(!elm)
        return NULL;

    void *res;
    enum ZIP_CMP eq = cmp(key, ZIP_KEY_PTR(elm));
    if(eq != ZIP_CMP_MORE) {
        res = __ZIP_ITER_KEY(cmp, fieldoffset, keyoffset, key,
                             cb, context, ZIP_ENTRY_PTR(elm)->left);
        if(res)
            return res;
    }

    if(eq == ZIP_CMP_EQ) {
        res = cb(context, elm);
        if(res)
            return res;
    }

    if(eq != ZIP_CMP_LESS) {
        res = __ZIP_ITER_KEY(cmp, fieldoffset, keyoffset, key,
                             cb, context, ZIP_ENTRY_PTR(elm)->right);
        if(res)
            return res;
    }

    return NULL;
}

void *
__ZIP_ZIP(unsigned short fieldoffset, void *left, void *right) {
    if(!left)
        return right;
    if(!right)
        return left;
    zip_elem *l = (zip_elem*)left;
    zip_elem *r = (zip_elem*)right;
    zip_elem *root = NULL;
    zip_elem **prev_edge = &root;
    while(l && r) {
        if(__ZIP_RANK_CMP(l, r) == ZIP_CMP_LESS) {
            *prev_edge = r;
            prev_edge = &ZIP_ENTRY_PTR(r)->left;
            r = ZIP_ENTRY_PTR(r)->left;
        } else {
            *prev_edge = l;
            prev_edge = &ZIP_ENTRY_PTR(l)->right;
            l = ZIP_ENTRY_PTR(l)->right;
        }
    }
    *prev_edge = (l) ? l : r;
    return root;
}

/* Walk down from cur and move all elements <= split-key to the left side. All
 * elements that are moved over have to be below left_rightmost. Returns the
 * hierarchy of elements that remain on the right side. */
static void
__ZIP_UNZIP_MOVE_LEFT(zip_cmp_cb cmp, unsigned short fieldoffset,
                      unsigned short keyoffset, const void *key,
                      zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->left) {
        zip_elem *next = ZIP_ENTRY_PTR(cur)->left;
        if(cmp(key, ZIP_KEY_PTR(next)) == ZIP_CMP_LESS) {
            cur = next;
            continue;
        }
        *fix_edge = next;
        ZIP_ENTRY_PTR(cur)->left = ZIP_ENTRY_PTR(next)->right;
        ZIP_ENTRY_PTR(next)->right = NULL;
        fix_edge = &ZIP_ENTRY_PTR(next)->right;
    }
}

static void
__ZIP_UNZIP_MOVE_RIGHT(zip_cmp_cb cmp, unsigned short fieldoffset,
                       unsigned short keyoffset, const void *key,
                       zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->right) {
        zip_elem *next = ZIP_ENTRY_PTR(cur)->right;
        if(cmp(key, ZIP_KEY_PTR(next)) != ZIP_CMP_LESS) {
            cur = next;
            continue;
        }
        *fix_edge = next;
        ZIP_ENTRY_PTR(cur)->right = ZIP_ENTRY_PTR(next)->left;
        ZIP_ENTRY_PTR(next)->left = NULL;
        fix_edge = &ZIP_ENTRY_PTR(next)->left;
    }
}

/* Split the tree into a left side with keys <= split-key and a right side with
 * key > split-key. */
void
__ZIP_UNZIP(zip_cmp_cb cmp, unsigned short fieldoffset,
            unsigned short keyoffset, const void *key,
            void *h, void *l, void *r) {
    zip_elem *prev;
    zip_head *head = (zip_head*)h;
    zip_head *left = (zip_head*)l;
    zip_head *right = (zip_head*)r;
    if(!head->root) {
        left->root = NULL;
        right->root = NULL;
        return;
    }
    zip_elem *cur = head->root;
    if(cmp(key, ZIP_KEY_PTR(cur)) != ZIP_CMP_LESS) {
        left->root = cur;
        do {
            prev = cur;
            cur = ZIP_ENTRY_PTR(cur)->right;
            if(!cur) {
                right->root = NULL;
                return;
            }
        } while(cmp(key, ZIP_KEY_PTR(cur)) != ZIP_CMP_LESS);
        ZIP_ENTRY_PTR(prev)->right = NULL;
        right->root = cur;
        __ZIP_UNZIP_MOVE_LEFT(cmp, fieldoffset, keyoffset, key,
                              &ZIP_ENTRY_PTR(prev)->right, cur);
    } else {
        right->root = cur;
        do {
            prev = cur;
            cur = ZIP_ENTRY_PTR(cur)->left;
            if(!cur) {
                left->root = NULL;
                return;
            }
        } while(cmp(key, ZIP_KEY_PTR(cur)) == ZIP_CMP_LESS);
        ZIP_ENTRY_PTR(prev)->left = NULL;
        left->root = cur;
        __ZIP_UNZIP_MOVE_RIGHT(cmp, fieldoffset, keyoffset, key,
                               &ZIP_ENTRY_PTR(prev)->left, cur);
    }
}

/**** amalgamated original file "/deps/parse_num.c" ****/

/* Originally released by the musl project (http://www.musl-libc.org/) under the
 * MIT license. Taken and adapted from the file src/stdlib/atoi.c 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


#include <string.h>
#include <stdlib.h>
#include <errno.h>

size_t
parseUInt64(const char *str, size_t size, uint64_t *result) {
    size_t i = 0;
    uint64_t n = 0, prev = 0;

    /* Hex */
    if(size > 2 && str[0] == '0' && (str[1] | 32) == 'x') {
        i = 2;
        for(; i < size; i++) {
            uint8_t c = (uint8_t)str[i] | 32;
            if(c >= '0' && c <= '9')
                c = (uint8_t)(c - '0');
            else if(c >= 'a' && c <='f')
                c = (uint8_t)(c - 'a' + 10);
            else if(c >= 'A' && c <='F')
                c = (uint8_t)(c - 'A' + 10);
            else
                break;
            n = (n << 4) | (c & 0xF);
            if(n < prev) /* Check for overflow */
                return 0;
            prev = n;
        }
        *result = n;
        return (i > 2) ? i : 0; /* 2 -> No digit was parsed */
    }

    /* Decimal */
    for(; i < size; i++) {
        if(str[i] < '0' || str[i] > '9')
            break;
        /* Fast multiplication: n*10 == (n*8) + (n*2) */
        n = (n << 3) + (n << 1) + (uint8_t)(str[i] - '0');
        if(n < prev) /* Check for overflow */
            return 0;
        prev = n;
    }
    *result = n;
    return i;
}

size_t
parseInt64(const char *str, size_t size, int64_t *result) {
    /* Negative value? */
    size_t i = 0;
    bool neg = false;
    if(*str == '-' || *str == '+') {
        neg = (*str == '-');
        i++;
    }

    /* Parse as unsigned */
    uint64_t n = 0;
    size_t len = parseUInt64(&str[i], size - i, &n);
    if(len == 0)
        return 0;

    /* Check for overflow, adjust and return */
    if(!neg) {
        if(n > 9223372036854775807UL)
            return 0;
        *result = (int64_t)n;
    } else {
        if(n > 9223372036854775808UL)
            return 0;
        *result = -(int64_t)n;
    }
    return len + i;
}

size_t parseDouble(const char *str, size_t size, double *result) {
    char buf[2000];
    if(size >= 2000)
        return 0;
    memcpy(buf, str, size);
    buf[size] = 0;
    errno = 0;
    char *endptr;
    *result = strtod(buf, &endptr);
    if(errno != 0 && errno != ERANGE)
        return 0;
    return (uintptr_t)endptr - (uintptr_t)buf;
}

/**** amalgamated original file "1_build/src_generated/open62541/namespace0_generated.c" ****/

/* WARNING: This is a generated file.
 * Any manual changes will be overwritten. */



/* HasDataSetReader - ns=0;i=15297 */

static UA_StatusCode function_namespace0_generated_0_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "IsReaderInGroup");
attr.displayName = UA_LOCALIZEDTEXT("", "HasDataSetReader");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15297LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HasDataSetReader"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_0_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15297LU));
}

/* HasDataSetWriter - ns=0;i=15296 */

static UA_StatusCode function_namespace0_generated_1_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "IsWriterInGroup");
attr.displayName = UA_LOCALIZEDTEXT("", "HasDataSetWriter");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15296LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HasDataSetWriter"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_1_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15296LU));
}

/* HasPubSubConnection - ns=0;i=14476 */

static UA_StatusCode function_namespace0_generated_2_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "PubSubConnectionOf");
attr.displayName = UA_LOCALIZEDTEXT("", "HasPubSubConnection");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14476LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HasPubSubConnection"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_2_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14476LU));
}

/* DataSetToWriter - ns=0;i=14936 */

static UA_StatusCode function_namespace0_generated_3_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "WriterToDataSet");
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetToWriter");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14936LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 33LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetToWriter"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_3_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14936LU));
}

/* AlwaysGeneratesEvent - ns=0;i=3065 */

static UA_StatusCode function_namespace0_generated_4_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "AlwaysGeneratedBy");
attr.displayName = UA_LOCALIZEDTEXT("", "AlwaysGeneratesEvent");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 41LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AlwaysGeneratesEvent"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_4_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU));
}

/* HasAddIn - ns=0;i=17604 */

static UA_StatusCode function_namespace0_generated_5_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "AddInOf");
attr.displayName = UA_LOCALIZEDTEXT("", "HasAddIn");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17604LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 32LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HasAddIn"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_5_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17604LU));
}

/* HasHistoricalConfiguration - ns=0;i=56 */

static UA_StatusCode function_namespace0_generated_6_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "HistoricalConfigurationOf");
attr.displayName = UA_LOCALIZEDTEXT("", "HasHistoricalConfiguration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 56LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 44LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HasHistoricalConfiguration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_6_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 56LU));
}

/* HasEffect - ns=0;i=54 */

static UA_StatusCode function_namespace0_generated_7_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "MayBeEffectedBy");
attr.displayName = UA_LOCALIZEDTEXT("", "HasEffect");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 54LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 32LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HasEffect"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_7_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 54LU));
}

/* HasCause - ns=0;i=53 */

static UA_StatusCode function_namespace0_generated_8_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "MayBeCausedBy");
attr.displayName = UA_LOCALIZEDTEXT("", "HasCause");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 53LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 32LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HasCause"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_8_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 53LU));
}

/* ToState - ns=0;i=52 */

static UA_StatusCode function_namespace0_generated_9_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "FromTransition");
attr.displayName = UA_LOCALIZEDTEXT("", "ToState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 52LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 32LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ToState"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_9_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 52LU));
}

/* FromState - ns=0;i=51 */

static UA_StatusCode function_namespace0_generated_10_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "ToTransition");
attr.displayName = UA_LOCALIZEDTEXT("", "FromState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 51LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 32LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "FromState"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_10_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 51LU));
}

/* DiagnosticInfo - ns=0;i=25 */

static UA_StatusCode function_namespace0_generated_11_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DiagnosticInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DiagnosticInfo"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_11_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25LU));
}

/* DataValue - ns=0;i=23 */

static UA_StatusCode function_namespace0_generated_12_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataValue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataValue"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_12_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23LU));
}

/* Structure - ns=0;i=22 */

static UA_StatusCode function_namespace0_generated_13_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Structure");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Structure"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_13_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU));
}

/* TimeZoneDataType - ns=0;i=8912 */

static UA_StatusCode function_namespace0_generated_14_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TimeZoneDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8912LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TimeZoneDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_14_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8912LU));
}

/* EUInformation - ns=0;i=887 */

static UA_StatusCode function_namespace0_generated_15_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "EUInformation");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 887LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EUInformation"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_15_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 887LU));
}

/* Range - ns=0;i=884 */

static UA_StatusCode function_namespace0_generated_16_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Range");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 884LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Range"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_16_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 884LU));
}

/* ModelChangeStructureDataType - ns=0;i=877 */

static UA_StatusCode function_namespace0_generated_17_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ModelChangeStructureDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 877LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModelChangeStructureDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_17_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 877LU));
}

/* SubscriptionDiagnosticsDataType - ns=0;i=874 */

static UA_StatusCode function_namespace0_generated_18_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_18_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU));
}

/* ServiceCounterDataType - ns=0;i=871 */

static UA_StatusCode function_namespace0_generated_19_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServiceCounterDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServiceCounterDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_19_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU));
}

/* SessionSecurityDiagnosticsDataType - ns=0;i=868 */

static UA_StatusCode function_namespace0_generated_20_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_20_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU));
}

/* SessionDiagnosticsDataType - ns=0;i=865 */

static UA_StatusCode function_namespace0_generated_21_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_21_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU));
}

/* ServerStatusDataType - ns=0;i=862 */

static UA_StatusCode function_namespace0_generated_22_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 862LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerStatusDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_22_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 862LU));
}

/* ServerDiagnosticsSummaryDataType - ns=0;i=859 */

static UA_StatusCode function_namespace0_generated_23_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummaryDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 859LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerDiagnosticsSummaryDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_23_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 859LU));
}

/* SamplingIntervalDiagnosticsDataType - ns=0;i=856 */

static UA_StatusCode function_namespace0_generated_24_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 856LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SamplingIntervalDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_24_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 856LU));
}

/* EnumValueType - ns=0;i=7594 */

static UA_StatusCode function_namespace0_generated_25_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7594LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumValueType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_25_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7594LU));
}

/* SignedSoftwareCertificate - ns=0;i=344 */

static UA_StatusCode function_namespace0_generated_26_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SignedSoftwareCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 344LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SignedSoftwareCertificate"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_26_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 344LU));
}

/* BuildInfo - ns=0;i=338 */

static UA_StatusCode function_namespace0_generated_27_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 338LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BuildInfo"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_27_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 338LU));
}

/* ApplicationDescription - ns=0;i=308 */

static UA_StatusCode function_namespace0_generated_28_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ApplicationDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 308LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ApplicationDescription"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_28_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 308LU));
}

/* Argument - ns=0;i=296 */

static UA_StatusCode function_namespace0_generated_29_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Argument");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Argument"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_29_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU));
}

/* AdditionalParametersType - ns=0;i=16313 */

static UA_StatusCode function_namespace0_generated_30_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AdditionalParametersType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16313LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AdditionalParametersType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_30_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16313LU));
}

/* PubSubConnectionDataType - ns=0;i=15617 */

static UA_StatusCode function_namespace0_generated_31_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PubSubConnectionDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15617LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PubSubConnectionDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_31_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15617LU));
}

/* PublishedDataSetSourceDataType - ns=0;i=15580 */

static UA_StatusCode function_namespace0_generated_32_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedDataSetSourceDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15580LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedDataSetSourceDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_32_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15580LU));
}

/* PublishedDataItemsDataType - ns=0;i=15581 */

static UA_StatusCode function_namespace0_generated_33_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedDataItemsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15581LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15580LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedDataItemsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_33_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15581LU));
}

/* PublishedDataSetDataType - ns=0;i=15578 */

static UA_StatusCode function_namespace0_generated_34_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedDataSetDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15578LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedDataSetDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_34_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15578LU));
}

/* DataTypeSchemaHeader - ns=0;i=15534 */

static UA_StatusCode function_namespace0_generated_35_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeSchemaHeader");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15534LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataTypeSchemaHeader"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_35_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15534LU));
}

/* DataSetMetaDataType - ns=0;i=14523 */

static UA_StatusCode function_namespace0_generated_36_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetMetaDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14523LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15534LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetMetaDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_36_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14523LU));
}

/* ConfigurationVersionDataType - ns=0;i=14593 */

static UA_StatusCode function_namespace0_generated_37_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ConfigurationVersionDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14593LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConfigurationVersionDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_37_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14593LU));
}

/* KeyValuePair - ns=0;i=14533 */

static UA_StatusCode function_namespace0_generated_38_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "KeyValuePair");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14533LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "KeyValuePair"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_38_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14533LU));
}

/* FieldMetaData - ns=0;i=14524 */

static UA_StatusCode function_namespace0_generated_39_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "FieldMetaData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14524LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "FieldMetaData"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_39_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14524LU));
}

/* PublishedVariableDataType - ns=0;i=14273 */

static UA_StatusCode function_namespace0_generated_40_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedVariableDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14273LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedVariableDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_40_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14273LU));
}

/* Union - ns=0;i=12756 */

static UA_StatusCode function_namespace0_generated_41_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Union");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12756LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Union"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_41_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12756LU));
}

/* TrustListDataType - ns=0;i=12554 */

static UA_StatusCode function_namespace0_generated_42_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TrustListDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12554LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 22LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TrustListDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_42_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12554LU));
}

/* LocalizedText - ns=0;i=21 */

static UA_StatusCode function_namespace0_generated_43_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "LocalizedText");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocalizedText"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_43_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU));
}

/* QualifiedName - ns=0;i=20 */

static UA_StatusCode function_namespace0_generated_44_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "QualifiedName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 20LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QualifiedName"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_44_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 20LU));
}

/* StatusCode - ns=0;i=19 */

static UA_StatusCode function_namespace0_generated_45_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "StatusCode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 19LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "StatusCode"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_45_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 19LU));
}

/* ExpandedNodeId - ns=0;i=18 */

static UA_StatusCode function_namespace0_generated_46_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ExpandedNodeId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 18LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ExpandedNodeId"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_46_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 18LU));
}

/* NodeId - ns=0;i=17 */

static UA_StatusCode function_namespace0_generated_47_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "NodeId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NodeId"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_47_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU));
}

/* XmlElement - ns=0;i=16 */

static UA_StatusCode function_namespace0_generated_48_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "XmlElement");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "XmlElement"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_48_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16LU));
}

/* ByteString - ns=0;i=15 */

static UA_StatusCode function_namespace0_generated_49_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ByteString");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ByteString"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_49_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU));
}

/* Image - ns=0;i=30 */

static UA_StatusCode function_namespace0_generated_50_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Image");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 30LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Image"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_50_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 30LU));
}

/* Guid - ns=0;i=14 */

static UA_StatusCode function_namespace0_generated_51_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Guid");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Guid"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_51_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14LU));
}

/* DateTime - ns=0;i=13 */

static UA_StatusCode function_namespace0_generated_52_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DateTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 13LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DateTime"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_52_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 13LU));
}

/* UtcTime - ns=0;i=294 */

static UA_StatusCode function_namespace0_generated_53_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UtcTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 13LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UtcTime"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_53_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU));
}

/* String - ns=0;i=12 */

static UA_StatusCode function_namespace0_generated_54_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "String");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "String"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_54_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU));
}

/* LocaleId - ns=0;i=295 */

static UA_StatusCode function_namespace0_generated_55_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocaleId"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_55_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU));
}

/* Boolean - ns=0;i=1 */

static UA_StatusCode function_namespace0_generated_56_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Boolean");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Boolean"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_56_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU));
}

/* Enumeration - ns=0;i=29 */

static UA_StatusCode function_namespace0_generated_57_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Enumeration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Enumeration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_57_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU));
}

/* ServerState - ns=0;i=852 */

static UA_StatusCode function_namespace0_generated_58_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 852LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerState"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_58_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 852LU));
}

/* RedundancySupport - ns=0;i=851 */

static UA_StatusCode function_namespace0_generated_59_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 851LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RedundancySupport"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_59_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 851LU));
}

/* EnumStrings - ns=0;i=7611 */

static UA_StatusCode function_namespace0_generated_60_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfLocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>None</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Cold</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Warm</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Hot</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Transparent</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>HotAndMirrored</Text>"
        "</LocalizedText>"
      "</ListOfLocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=7611: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7611LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 851LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumStrings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_60_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7611LU));
}

/* ApplicationType - ns=0;i=307 */

static UA_StatusCode function_namespace0_generated_61_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ApplicationType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 307LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ApplicationType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_61_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 307LU));
}

/* EnumStrings - ns=0;i=7597 */

static UA_StatusCode function_namespace0_generated_62_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfLocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Server</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Client</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>ClientAndServer</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>DiscoveryServer</Text>"
        "</LocalizedText>"
      "</ListOfLocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=7597: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7597LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 307LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumStrings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_62_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7597LU));
}

/* MessageSecurityMode - ns=0;i=302 */

static UA_StatusCode function_namespace0_generated_63_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "MessageSecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 302LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MessageSecurityMode"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_63_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 302LU));
}

/* EnumStrings - ns=0;i=7595 */

static UA_StatusCode function_namespace0_generated_64_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfLocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Invalid</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>None</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Sign</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>SignAndEncrypt</Text>"
        "</LocalizedText>"
      "</ListOfLocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=7595: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7595LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 302LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumStrings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_64_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7595LU));
}

/* PubSubState - ns=0;i=14647 */

static UA_StatusCode function_namespace0_generated_65_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PubSubState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PubSubState"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_65_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU));
}

/* EnumStrings - ns=0;i=14648 */

static UA_StatusCode function_namespace0_generated_66_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfLocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Disabled</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Paused</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Operational</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Error</Text>"
        "</LocalizedText>"
      "</ListOfLocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14648: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14648LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumStrings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_66_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14648LU));
}

/* TrustListMasks - ns=0;i=12552 */

static UA_StatusCode function_namespace0_generated_67_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TrustListMasks");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12552LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TrustListMasks"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_67_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12552LU));
}

/* EnumValues - ns=0;i=12553 */

static UA_StatusCode function_namespace0_generated_68_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 6;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7594LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>0</Value>"
              "<DisplayName>"
                "<Text>None</Text>"
              "</DisplayName>"
              "<Description>"
                "<Text>No fields are provided.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>1</Value>"
              "<DisplayName>"
                "<Text>TrustedCertificates</Text>"
              "</DisplayName>"
              "<Description>"
                "<Text>The TrustedCertificates are provided.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>2</Value>"
              "<DisplayName>"
                "<Text>TrustedCrls</Text>"
              "</DisplayName>"
              "<Description>"
                "<Text>The TrustedCrls are provided.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>4</Value>"
              "<DisplayName>"
                "<Text>IssuerCertificates</Text>"
              "</DisplayName>"
              "<Description>"
                "<Text>The IssuerCertificates are provided.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>8</Value>"
              "<DisplayName>"
                "<Text>IssuerCrls</Text>"
              "</DisplayName>"
              "<Description>"
                "<Text>The IssuerCrls are provided.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>15</Value>"
              "<DisplayName>"
                "<Text>All</Text>"
              "</DisplayName>"
              "<Description>"
                "<Text>All fields are provided.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=12553: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12553LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12552LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumValues"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_68_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12553LU));
}

/* AxisScaleEnumeration - ns=0;i=12077 */

static UA_StatusCode function_namespace0_generated_69_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AxisScaleEnumeration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12077LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AxisScaleEnumeration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_69_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12077LU));
}

/* EnumStrings - ns=0;i=12078 */

static UA_StatusCode function_namespace0_generated_70_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfLocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Linear</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Log</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>Ln</Text>"
        "</LocalizedText>"
      "</ListOfLocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=12078: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12078LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12077LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumStrings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_70_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12078LU));
}

/* NamingRuleType - ns=0;i=120 */

static UA_StatusCode function_namespace0_generated_71_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRuleType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 29LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamingRuleType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_71_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU));
}

/* EnumValues - ns=0;i=12169 */

static UA_StatusCode function_namespace0_generated_72_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7594LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>1</Value>"
              "<DisplayName>"
                "<Locale>"
                "</Locale>"
                "<Text>Mandatory</Text>"
              "</DisplayName>"
              "<Description>"
                "<Locale>"
                "</Locale>"
                "<Text>The BrowseName must appear in all instances of the type.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>2</Value>"
              "<DisplayName>"
                "<Locale>"
                "</Locale>"
                "<Text>Optional</Text>"
              "</DisplayName>"
              "<Description>"
                "<Locale>"
                "</Locale>"
                "<Text>The BrowseName may appear in an instance of the type.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=7616</Identifier>"
          "</TypeId>"
          "<Body>"
            "<EnumValueType>"
              "<Value>3</Value>"
              "<DisplayName>"
                "<Locale>"
                "</Locale>"
                "<Text>Constraint</Text>"
              "</DisplayName>"
              "<Description>"
                "<Locale>"
                "</Locale>"
                "<Text>The modelling rule defines a constraint and the BrowseName is not used in an instance of the type.</Text>"
              "</Description>"
            "</EnumValueType>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=12169: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12169LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumValues"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_72_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12169LU));
}

/* Number - ns=0;i=26 */

static UA_StatusCode function_namespace0_generated_73_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Number");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Number"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_73_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU));
}

/* Decimal - ns=0;i=50 */

static UA_StatusCode function_namespace0_generated_74_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Decimal");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 50LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Decimal"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_74_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 50LU));
}

/* UInteger - ns=0;i=28 */

static UA_StatusCode function_namespace0_generated_75_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "UInteger");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 28LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UInteger"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_75_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 28LU));
}

/* UInt64 - ns=0;i=9 */

static UA_StatusCode function_namespace0_generated_76_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UInt64");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 28LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UInt64"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_76_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9LU));
}

/* UInt32 - ns=0;i=7 */

static UA_StatusCode function_namespace0_generated_77_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UInt32");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 28LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UInt32"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_77_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU));
}

/* VersionTime - ns=0;i=20998 */

static UA_StatusCode function_namespace0_generated_78_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "VersionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 20998LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "VersionTime"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_78_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 20998LU));
}

/* DataSetFieldContentMask - ns=0;i=15583 */

static UA_StatusCode function_namespace0_generated_79_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetFieldContentMask");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15583LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetFieldContentMask"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_79_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15583LU));
}

/* OptionSetValues - ns=0;i=15584 */

static UA_StatusCode function_namespace0_generated_80_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfLocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>StatusCode</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>SourceTimestamp</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>ServerTimestamp</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>SourcePicoSeconds</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>ServerPicoSeconds</Text>"
        "</LocalizedText>"
        "<LocalizedText>"
          "<Locale>"
          "</Locale>"
          "<Text>RawDataEncoding</Text>"
        "</LocalizedText>"
      "</ListOfLocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=15584: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OptionSetValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15584LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15583LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OptionSetValues"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_80_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15584LU));
}

/* UInt16 - ns=0;i=5 */

static UA_StatusCode function_namespace0_generated_81_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UInt16");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 28LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UInt16"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_81_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU));
}

/* Byte - ns=0;i=3 */

static UA_StatusCode function_namespace0_generated_82_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Byte");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 28LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Byte"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_82_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3LU));
}

/* Integer - ns=0;i=27 */

static UA_StatusCode function_namespace0_generated_83_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Integer");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 27LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Integer"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_83_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 27LU));
}

/* Int64 - ns=0;i=8 */

static UA_StatusCode function_namespace0_generated_84_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Int64");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 27LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Int64"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_84_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8LU));
}

/* Int32 - ns=0;i=6 */

static UA_StatusCode function_namespace0_generated_85_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Int32");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 6LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 27LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Int32"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_85_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 6LU));
}

/* Int16 - ns=0;i=4 */

static UA_StatusCode function_namespace0_generated_86_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Int16");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 4LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 27LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Int16"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_86_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 4LU));
}

/* SByte - ns=0;i=2 */

static UA_StatusCode function_namespace0_generated_87_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SByte");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 27LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SByte"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_87_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2LU));
}

/* Double - ns=0;i=11 */

static UA_StatusCode function_namespace0_generated_88_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Double");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Double"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_88_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11LU));
}

/* Duration - ns=0;i=290 */

static UA_StatusCode function_namespace0_generated_89_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Duration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Duration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_89_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU));
}

/* Float - ns=0;i=10 */

static UA_StatusCode function_namespace0_generated_90_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Float");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 10LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Float"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_90_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 10LU));
}

/* DataItemType - ns=0;i=2365 */

static UA_StatusCode function_namespace0_generated_91_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataItemType");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A variable that contains live automation data.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2365LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataItemType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_91_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2365LU));
}

/* DiscreteItemType - ns=0;i=2372 */

static UA_StatusCode function_namespace0_generated_92_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.isAbstract = true;
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DiscreteItemType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2372LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2365LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DiscreteItemType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_92_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2372LU));
}

/* MultiStateDiscreteType - ns=0;i=2376 */

static UA_StatusCode function_namespace0_generated_93_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 28LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MultiStateDiscreteType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2376LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2372LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MultiStateDiscreteType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_93_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2376LU));
}

/* EnumStrings - ns=0;i=2377 */

static UA_StatusCode function_namespace0_generated_94_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2377LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2376LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumStrings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_94_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2377LU));
}

/* TwoStateDiscreteType - ns=0;i=2373 */

static UA_StatusCode function_namespace0_generated_95_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TwoStateDiscreteType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2373LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2372LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TwoStateDiscreteType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_95_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2373LU));
}

/* TrueState - ns=0;i=2375 */

static UA_StatusCode function_namespace0_generated_96_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TrueState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2375LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2373LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TrueState"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_96_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2375LU));
}

/* FalseState - ns=0;i=2374 */

static UA_StatusCode function_namespace0_generated_97_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "FalseState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2374LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2373LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "FalseState"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_97_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2374LU));
}

/* MultiStateValueDiscreteType - ns=0;i=11238 */

static UA_StatusCode function_namespace0_generated_98_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MultiStateValueDiscreteType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11238LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2372LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MultiStateValueDiscreteType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_98_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11238LU));
}

/* ValueAsText - ns=0;i=11461 */

static UA_StatusCode function_namespace0_generated_99_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ValueAsText");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11461LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11238LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ValueAsText"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_99_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11461LU));
}

/* EnumValues - ns=0;i=11241 */

static UA_StatusCode function_namespace0_generated_100_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7594LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11241LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11238LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumValues"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_100_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11241LU));
}

/* AnalogItemType - ns=0;i=2368 */

static UA_StatusCode function_namespace0_generated_101_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 26LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AnalogItemType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2368LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2365LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AnalogItemType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_101_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2368LU));
}

/* EngineeringUnits - ns=0;i=2371 */

static UA_StatusCode function_namespace0_generated_102_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 887LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EngineeringUnits");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2371LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2368LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EngineeringUnits"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_102_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2371LU));
}

/* InstrumentRange - ns=0;i=2370 */

static UA_StatusCode function_namespace0_generated_103_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 884LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InstrumentRange");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2370LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2368LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InstrumentRange"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_103_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2370LU));
}

/* EURange - ns=0;i=2369 */

static UA_StatusCode function_namespace0_generated_104_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 3;
attr.accessLevel = 3;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 884LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EURange");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2369LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2368LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EURange"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_104_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2369LU));
}

/* ValuePrecision - ns=0;i=2367 */

static UA_StatusCode function_namespace0_generated_105_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ValuePrecision");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "The maximum precision that the server can maintain for the item based on restrictions in the target environment.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2367LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2365LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ValuePrecision"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_105_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2367LU));
}

/* Definition - ns=0;i=2366 */

static UA_StatusCode function_namespace0_generated_106_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Definition");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A vendor-specific, human readable string that specifies how the value of this DataItem is calculated.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2366LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2365LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Definition"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_106_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2366LU));
}

/* SubscribedDataSetType - ns=0;i=15108 */

static UA_StatusCode function_namespace0_generated_107_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscribedDataSetType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscribedDataSetType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_107_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU));
}

/* TargetVariablesType - ns=0;i=15111 */

static UA_StatusCode function_namespace0_generated_108_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TargetVariablesType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15111LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TargetVariablesType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_108_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15111LU));
}

/* RemoveTargetVariables - ns=0;i=15118 */

static UA_StatusCode function_namespace0_generated_109_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveTargetVariables");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15118LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveTargetVariables"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15118LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15111LU), false);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_109_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15118LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=15120 */

static UA_StatusCode function_namespace0_generated_110_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>AddResults</Name>"
              "<DataType>"
                "<Identifier>i=19</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=15120: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15120LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15118LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_110_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15120LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=15119 */

static UA_StatusCode function_namespace0_generated_111_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConfigurationVersion</Name>"
              "<DataType>"
                "<Identifier>i=14593</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=15119: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15119LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15118LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_111_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15119LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddTargetVariables - ns=0;i=15115 */

static UA_StatusCode function_namespace0_generated_112_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddTargetVariables");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15115LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddTargetVariables"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15115LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15111LU), false);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_112_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15115LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=15117 */

static UA_StatusCode function_namespace0_generated_113_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>AddResults</Name>"
              "<DataType>"
                "<Identifier>i=19</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=15117: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15117LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15115LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_113_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15117LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=15116 */

static UA_StatusCode function_namespace0_generated_114_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConfigurationVersion</Name>"
              "<DataType>"
                "<Identifier>i=14593</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=15116: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15116LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15115LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_114_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15116LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* TargetVariables - ns=0;i=15114 */

static UA_StatusCode function_namespace0_generated_115_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TargetVariables");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15114LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15111LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TargetVariables"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_115_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15114LU));
}

/* DataSetReaderMessageType - ns=0;i=21104 */

static UA_StatusCode function_namespace0_generated_116_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetReaderMessageType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21104LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetReaderMessageType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_116_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21104LU));
}

/* UadpDataSetReaderMessageType - ns=0;i=21116 */

static UA_StatusCode function_namespace0_generated_117_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UadpDataSetReaderMessageType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21116LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21104LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UadpDataSetReaderMessageType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_117_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21116LU));
}

/* DataSetReaderTransportType - ns=0;i=15319 */

static UA_StatusCode function_namespace0_generated_118_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetReaderTransportType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15319LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetReaderTransportType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_118_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15319LU));
}

/* BrokerDataSetReaderTransportType - ns=0;i=21142 */

static UA_StatusCode function_namespace0_generated_119_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "BrokerDataSetReaderTransportType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrokerDataSetReaderTransportType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21142LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15319LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_119_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21142LU));
}

/* DataSetReaderType - ns=0;i=15306 */

static UA_StatusCode function_namespace0_generated_120_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetReaderType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetReaderType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_120_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU));
}

/* MessageSettings - ns=0;i=21103 */

static UA_StatusCode function_namespace0_generated_121_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "MessageSettings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21103LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MessageSettings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21104LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_121_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21103LU));
}

/* MessageReceiveTimeout - ns=0;i=21102 */

static UA_StatusCode function_namespace0_generated_122_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MessageReceiveTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21102LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MessageReceiveTimeout"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_122_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21102LU));
}

/* DataSetFieldContentMask - ns=0;i=21101 */

static UA_StatusCode function_namespace0_generated_123_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15583LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetFieldContentMask");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21101LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetFieldContentMask"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_123_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21101LU));
}

/* DataSetMetaData - ns=0;i=21100 */

static UA_StatusCode function_namespace0_generated_124_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14523LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetMetaData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21100LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetMetaData"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_124_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21100LU));
}

/* DataSetWriterId - ns=0;i=21099 */

static UA_StatusCode function_namespace0_generated_125_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetWriterId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21099LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetWriterId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_125_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21099LU));
}

/* WriterGroupId - ns=0;i=21098 */

static UA_StatusCode function_namespace0_generated_126_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriterGroupId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriterGroupId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_126_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21098LU));
}

/* PublisherId - ns=0;i=21097 */

static UA_StatusCode function_namespace0_generated_127_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublisherId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21097LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublisherId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_127_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21097LU));
}

/* DataSetReaderProperties - ns=0;i=17494 */

static UA_StatusCode function_namespace0_generated_128_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14533LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetReaderProperties");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17494LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetReaderProperties"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_128_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17494LU));
}

/* SubscribedDataSet - ns=0;i=15316 */

static UA_StatusCode function_namespace0_generated_129_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscribedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15316LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscribedDataSet"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_129_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15316LU));
}

/* TransportSettings - ns=0;i=15311 */

static UA_StatusCode function_namespace0_generated_130_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TransportSettings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15311LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportSettings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15319LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_130_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15311LU));
}

/* DataSetWriterMessageType - ns=0;i=21096 */

static UA_StatusCode function_namespace0_generated_131_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetWriterMessageType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21096LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetWriterMessageType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_131_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21096LU));
}

/* UadpDataSetWriterMessageType - ns=0;i=21111 */

static UA_StatusCode function_namespace0_generated_132_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UadpDataSetWriterMessageType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21111LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21096LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UadpDataSetWriterMessageType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_132_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21111LU));
}

/* WriterGroupMessageType - ns=0;i=17998 */

static UA_StatusCode function_namespace0_generated_133_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "WriterGroupMessageType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17998LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriterGroupMessageType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_133_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17998LU));
}

/* UadpWriterGroupMessageType - ns=0;i=21105 */

static UA_StatusCode function_namespace0_generated_134_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UadpWriterGroupMessageType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21105LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17998LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UadpWriterGroupMessageType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_134_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21105LU));
}

/* SelectionListType - ns=0;i=16309 */

static UA_StatusCode function_namespace0_generated_135_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SelectionListType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16309LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SelectionListType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_135_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16309LU));
}

/* SelectionDescriptions - ns=0;i=17633 */

static UA_StatusCode function_namespace0_generated_136_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SelectionDescriptions");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17633LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16309LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SelectionDescriptions"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_136_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17633LU));
}

/* Selections - ns=0;i=17632 */

static UA_StatusCode function_namespace0_generated_137_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Selections");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17632LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16309LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Selections"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_137_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17632LU));
}

/* RestrictToList - ns=0;i=16312 */

static UA_StatusCode function_namespace0_generated_138_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RestrictToList");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16312LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16309LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RestrictToList"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_138_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16312LU));
}

/* PubSubStatusType - ns=0;i=14643 */

static UA_StatusCode function_namespace0_generated_139_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PubSubStatusType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PubSubStatusType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_139_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU));
}

/* Status - ns=0;i=15307 */

static UA_StatusCode function_namespace0_generated_140_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Status");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15307LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Status"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_140_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15307LU));
}

/* State - ns=0;i=15308 */

static UA_StatusCode function_namespace0_generated_141_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15308LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15307LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_141_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15308LU));
}

/* Disable - ns=0;i=14646 */

static UA_StatusCode function_namespace0_generated_142_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Disable");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14646LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Disable"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_142_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14646LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* Enable - ns=0;i=14645 */

static UA_StatusCode function_namespace0_generated_143_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Enable");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14645LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Enable"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_143_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14645LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* State - ns=0;i=14644 */

static UA_StatusCode function_namespace0_generated_144_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14644LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_144_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14644LU));
}

/* StandaloneSubscribedDataSetType - ns=0;i=23828 */

static UA_StatusCode function_namespace0_generated_145_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "StandaloneSubscribedDataSetType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23828LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "StandaloneSubscribedDataSetType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_145_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23828LU));
}

/* IsConnected - ns=0;i=23831 */

static UA_StatusCode function_namespace0_generated_146_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "IsConnected");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23831LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23828LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "IsConnected"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_146_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23831LU));
}

/* DataSetMetaData - ns=0;i=23830 */

static UA_StatusCode function_namespace0_generated_147_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14523LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetMetaData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23830LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23828LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetMetaData"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_147_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23830LU));
}

/* SubscribedDataSet - ns=0;i=23829 */

static UA_StatusCode function_namespace0_generated_148_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscribedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23829LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23828LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscribedDataSet"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_148_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23829LU));
}

/* SubscribedDataSetFolderType - ns=0;i=23795 */

static UA_StatusCode function_namespace0_generated_149_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscribedDataSetFolderType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 61LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscribedDataSetFolderType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_149_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU));
}

/* RemoveDataSetFolder - ns=0;i=23819 */

static UA_StatusCode function_namespace0_generated_150_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveDataSetFolder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23819LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveDataSetFolder"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_150_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23819LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23820 */

static UA_StatusCode function_namespace0_generated_151_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetFolderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23820: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23820LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23819LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_151_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23820LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddDataSetFolder - ns=0;i=23816 */

static UA_StatusCode function_namespace0_generated_152_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddDataSetFolder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddDataSetFolder"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_152_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23816LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=23818 */

static UA_StatusCode function_namespace0_generated_153_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetFolderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23818: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23818LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_153_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23818LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23817 */

static UA_StatusCode function_namespace0_generated_154_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Name</Name>"
              "<DataType>"
                "<Identifier>i=12</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23817: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23817LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_154_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23817LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* RemoveSubscribedDataSet - ns=0;i=23814 */

static UA_StatusCode function_namespace0_generated_155_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveSubscribedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23814LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveSubscribedDataSet"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_155_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23814LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23815 */

static UA_StatusCode function_namespace0_generated_156_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscribedDataSetNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23815: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23815LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23814LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_156_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23815LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddSubscribedDataSet - ns=0;i=23811 */

static UA_StatusCode function_namespace0_generated_157_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddSubscribedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23811LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddSubscribedDataSet"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_157_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23811LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=23813 */

static UA_StatusCode function_namespace0_generated_158_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscribedDataSetNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23813: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23813LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23811LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_158_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23813LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23812 */

static UA_StatusCode function_namespace0_generated_159_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscribedDataSet</Name>"
              "<DataType>"
                "<Identifier>i=23600</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23812: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23812LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23811LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_159_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23812LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* <StandaloneSubscribedDataSetName> - ns=0;i=23807 */

static UA_StatusCode function_namespace0_generated_160_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<StandaloneSubscribedDataSetName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23807LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<StandaloneSubscribedDataSetName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23828LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_160_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23807LU));
}

/* IsConnected - ns=0;i=23810 */

static UA_StatusCode function_namespace0_generated_161_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "IsConnected");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23810LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23807LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "IsConnected"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_161_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23810LU));
}

/* DataSetMetaData - ns=0;i=23809 */

static UA_StatusCode function_namespace0_generated_162_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14523LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetMetaData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23809LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23807LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetMetaData"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_162_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23809LU));
}

/* SubscribedDataSet - ns=0;i=23808 */

static UA_StatusCode function_namespace0_generated_163_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscribedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23808LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23807LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscribedDataSet"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15108LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_163_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23808LU));
}

/* <SubscribedDataSetFolderName> - ns=0;i=23796 */

static UA_StatusCode function_namespace0_generated_164_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<SubscribedDataSetFolderName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23796LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 35LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<SubscribedDataSetFolderName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_164_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23796LU));
}

/* RemoveDataSetFolder - ns=0;i=23805 */

static UA_StatusCode function_namespace0_generated_165_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveDataSetFolder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23805LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23796LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveDataSetFolder"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_165_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23805LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23806 */

static UA_StatusCode function_namespace0_generated_166_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetFolderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23806: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23806LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23805LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_166_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23806LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddDataSetFolder - ns=0;i=23802 */

static UA_StatusCode function_namespace0_generated_167_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddDataSetFolder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23802LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23796LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddDataSetFolder"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_167_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23802LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=23804 */

static UA_StatusCode function_namespace0_generated_168_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetFolderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23804: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23804LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23802LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_168_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23804LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23803 */

static UA_StatusCode function_namespace0_generated_169_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Name</Name>"
              "<DataType>"
                "<Identifier>i=12</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23803: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23803LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23802LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_169_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23803LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* RemoveSubscribedDataSet - ns=0;i=23800 */

static UA_StatusCode function_namespace0_generated_170_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveSubscribedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23800LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23796LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveSubscribedDataSet"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_170_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23800LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23801 */

static UA_StatusCode function_namespace0_generated_171_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscribedDataSetNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23801: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23801LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23800LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_171_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23801LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddSubscribedDataSet - ns=0;i=23797 */

static UA_StatusCode function_namespace0_generated_172_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddSubscribedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23797LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23796LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddSubscribedDataSet"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_172_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23797LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=23799 */

static UA_StatusCode function_namespace0_generated_173_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscribedDataSetNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23799: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23799LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23797LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_173_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23799LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=23798 */

static UA_StatusCode function_namespace0_generated_174_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscribedDataSet</Name>"
              "<DataType>"
                "<Identifier>i=23600</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=23798: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23798LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23797LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_174_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23798LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* DataSetWriterType - ns=0;i=15298 */

static UA_StatusCode function_namespace0_generated_175_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetWriterType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetWriterType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_175_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU));
}

/* KeyFrameCount - ns=0;i=21094 */

static UA_StatusCode function_namespace0_generated_176_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "KeyFrameCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21094LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "KeyFrameCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_176_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21094LU));
}

/* DataSetFieldContentMask - ns=0;i=21093 */

static UA_StatusCode function_namespace0_generated_177_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15583LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetFieldContentMask");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21093LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetFieldContentMask"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_177_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21093LU));
}

/* DataSetWriterId - ns=0;i=21092 */

static UA_StatusCode function_namespace0_generated_178_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetWriterId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21092LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetWriterId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_178_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21092LU));
}

/* DataSetWriterProperties - ns=0;i=17493 */

static UA_StatusCode function_namespace0_generated_179_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14533LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetWriterProperties");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17493LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetWriterProperties"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_179_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17493LU));
}

/* TransportSettings - ns=0;i=15303 */

static UA_StatusCode function_namespace0_generated_180_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TransportSettings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15303LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportSettings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_180_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15303LU));
}

/* Status - ns=0;i=15299 */

static UA_StatusCode function_namespace0_generated_181_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Status");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15299LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Status"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_181_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15299LU));
}

/* State - ns=0;i=15300 */

static UA_StatusCode function_namespace0_generated_182_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15300LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15299LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_182_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15300LU));
}

/* PubSubGroupType - ns=0;i=14232 */

static UA_StatusCode function_namespace0_generated_183_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PubSubGroupType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14232LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PubSubGroupType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_183_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14232LU));
}

/* ReaderGroupType - ns=0;i=17999 */

static UA_StatusCode function_namespace0_generated_184_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ReaderGroupType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17999LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14232LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReaderGroupType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_184_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17999LU));
}

/* RemoveDataSetReader - ns=0;i=21085 */

static UA_StatusCode function_namespace0_generated_185_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveDataSetReader");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21085LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17999LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveDataSetReader"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_185_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21085LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=21086 */

static UA_StatusCode function_namespace0_generated_186_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetReaderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=15623</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=21086: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21086LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21085LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_186_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21086LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddDataSetReader - ns=0;i=21082 */

static UA_StatusCode function_namespace0_generated_187_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddDataSetReader");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21082LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17999LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddDataSetReader"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_187_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21082LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=21084 */

static UA_StatusCode function_namespace0_generated_188_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetReaderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=21084: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21084LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21082LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_188_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21084LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=21083 */

static UA_StatusCode function_namespace0_generated_189_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Configuration</Name>"
              "<DataType>"
                "<Identifier>i=15623</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=21083: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21083LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21082LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_189_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21083LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* <DataSetReaderName> - ns=0;i=18076 */

static UA_StatusCode function_namespace0_generated_190_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<DataSetReaderName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 18076LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17999LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15297LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<DataSetReaderName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15306LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_190_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 18076LU));
}

/* WriterGroupType - ns=0;i=17725 */

static UA_StatusCode function_namespace0_generated_191_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "WriterGroupType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14232LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriterGroupType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_191_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU));
}

/* RemoveDataSetWriter - ns=0;i=17992 */

static UA_StatusCode function_namespace0_generated_192_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveDataSetWriter");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17992LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveDataSetWriter"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_192_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17992LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=17993 */

static UA_StatusCode function_namespace0_generated_193_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetWriterNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17993: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17993LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17992LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_193_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17993LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddDataSetWriter - ns=0;i=17969 */

static UA_StatusCode function_namespace0_generated_194_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddDataSetWriter");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17969LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddDataSetWriter"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_194_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17969LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=17987 */

static UA_StatusCode function_namespace0_generated_195_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetWriterNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17987: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17987LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17969LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_195_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17987LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=17976 */

static UA_StatusCode function_namespace0_generated_196_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Configuration</Name>"
              "<DataType>"
                "<Identifier>i=15597</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17976: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17976LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17969LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_196_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17976LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* <DataSetWriterName> - ns=0;i=17743 */

static UA_StatusCode function_namespace0_generated_197_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<DataSetWriterName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17743LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15296LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<DataSetWriterName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15298LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_197_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17743LU));
}

/* Status - ns=0;i=17749 */

static UA_StatusCode function_namespace0_generated_198_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Status");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17749LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17743LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Status"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_198_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17749LU));
}

/* State - ns=0;i=17750 */

static UA_StatusCode function_namespace0_generated_199_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17750LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17749LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_199_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17750LU));
}

/* DataSetFieldContentMask - ns=0;i=17745 */

static UA_StatusCode function_namespace0_generated_200_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15583LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetFieldContentMask");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17745LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17743LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetFieldContentMask"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_200_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17745LU));
}

/* DataSetWriterId - ns=0;i=17744 */

static UA_StatusCode function_namespace0_generated_201_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetWriterId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17744LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17743LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetWriterId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_201_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17744LU));
}

/* DataSetWriterProperties - ns=0;i=17490 */

static UA_StatusCode function_namespace0_generated_202_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14533LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetWriterProperties");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17490LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17743LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetWriterProperties"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_202_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17490LU));
}

/* LocaleIds - ns=0;i=17740 */

static UA_StatusCode function_namespace0_generated_203_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17740LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocaleIds"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_203_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17740LU));
}

/* Priority - ns=0;i=17739 */

static UA_StatusCode function_namespace0_generated_204_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Priority");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17739LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Priority"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_204_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17739LU));
}

/* KeepAliveTime - ns=0;i=17738 */

static UA_StatusCode function_namespace0_generated_205_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "KeepAliveTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17738LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "KeepAliveTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_205_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17738LU));
}

/* PublishingInterval - ns=0;i=17737 */

static UA_StatusCode function_namespace0_generated_206_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17737LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingInterval"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_206_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17737LU));
}

/* WriterGroupId - ns=0;i=17736 */

static UA_StatusCode function_namespace0_generated_207_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriterGroupId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17736LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriterGroupId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_207_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17736LU));
}

/* MaxNetworkMessageSize - ns=0;i=17724 */

static UA_StatusCode function_namespace0_generated_208_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNetworkMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17724LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14232LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNetworkMessageSize"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_208_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17724LU));
}

/* SecurityGroupId - ns=0;i=15927 */

static UA_StatusCode function_namespace0_generated_209_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityGroupId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15927LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14232LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityGroupId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_209_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15927LU));
}

/* Status - ns=0;i=15265 */

static UA_StatusCode function_namespace0_generated_210_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Status");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15265LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14232LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Status"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_210_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15265LU));
}

/* State - ns=0;i=15266 */

static UA_StatusCode function_namespace0_generated_211_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15266LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15265LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_211_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15266LU));
}

/* ConnectionTransportType - ns=0;i=17721 */

static UA_StatusCode function_namespace0_generated_212_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "ConnectionTransportType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17721LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConnectionTransportType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_212_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17721LU));
}

/* NetworkAddressType - ns=0;i=21145 */

static UA_StatusCode function_namespace0_generated_213_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "NetworkAddressType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21145LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NetworkAddressType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_213_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21145LU));
}

/* NetworkAddressUrlType - ns=0;i=21147 */

static UA_StatusCode function_namespace0_generated_214_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "NetworkAddressUrlType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21147LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21145LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NetworkAddressUrlType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_214_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21147LU));
}

/* Url - ns=0;i=21149 */

static UA_StatusCode function_namespace0_generated_215_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Url");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21149LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21147LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Url"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_215_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21149LU));
}

/* NetworkInterface - ns=0;i=21146 */

static UA_StatusCode function_namespace0_generated_216_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NetworkInterface");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21146LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21145LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NetworkInterface"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_216_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21146LU));
}

/* PubSubConnectionType - ns=0;i=14209 */

static UA_StatusCode function_namespace0_generated_217_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PubSubConnectionType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PubSubConnectionType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_217_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU));
}

/* ConnectionProperties - ns=0;i=17485 */

static UA_StatusCode function_namespace0_generated_218_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14533LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConnectionProperties");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17485LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConnectionProperties"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_218_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17485LU));
}

/* AddReaderGroup - ns=0;i=17465 */

static UA_StatusCode function_namespace0_generated_219_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddReaderGroup");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17465LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddReaderGroup"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_219_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17465LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=17508 */

static UA_StatusCode function_namespace0_generated_220_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>GroupId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17508: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17508LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17465LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_220_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17508LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=17507 */

static UA_StatusCode function_namespace0_generated_221_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Configuration</Name>"
              "<DataType>"
                "<Identifier>i=15520</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17507: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17507LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17465LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_221_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17507LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddWriterGroup - ns=0;i=17427 */

static UA_StatusCode function_namespace0_generated_222_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddWriterGroup");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17427LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddWriterGroup"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_222_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17427LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=17456 */

static UA_StatusCode function_namespace0_generated_223_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>GroupId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17456: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17456LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17427LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_223_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17456LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=17428 */

static UA_StatusCode function_namespace0_generated_224_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Configuration</Name>"
              "<DataType>"
                "<Identifier>i=15480</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17428: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17428LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17427LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_224_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17428LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* <ReaderGroupName> - ns=0;i=17325 */

static UA_StatusCode function_namespace0_generated_225_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<ReaderGroupName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17325LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<ReaderGroupName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17999LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_225_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17325LU));
}

/* <WriterGroupName> - ns=0;i=17310 */

static UA_StatusCode function_namespace0_generated_226_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<WriterGroupName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17310LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<WriterGroupName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17725LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_226_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17310LU));
}

/* TransportProfileUri - ns=0;i=17306 */

static UA_StatusCode function_namespace0_generated_227_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProfileUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportProfileUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16309LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_227_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17306LU));
}

/* Selections - ns=0;i=17710 */

static UA_StatusCode function_namespace0_generated_228_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Selections");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17710LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17306LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Selections"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_228_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17710LU));
}

/* TransportSettings - ns=0;i=17203 */

static UA_StatusCode function_namespace0_generated_229_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TransportSettings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17203LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportSettings"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17721LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_229_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17203LU));
}

/* Status - ns=0;i=14600 */

static UA_StatusCode function_namespace0_generated_230_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Status");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14600LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Status"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_230_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14600LU));
}

/* State - ns=0;i=14601 */

static UA_StatusCode function_namespace0_generated_231_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14601LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14600LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_231_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14601LU));
}

/* PublisherId - ns=0;i=14595 */

static UA_StatusCode function_namespace0_generated_232_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublisherId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14595LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublisherId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_232_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14595LU));
}

/* RemoveGroup - ns=0;i=14225 */

static UA_StatusCode function_namespace0_generated_233_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveGroup");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14225LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveGroup"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_233_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14225LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=14226 */

static UA_StatusCode function_namespace0_generated_234_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>GroupId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14226: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14226LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14225LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_234_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14226LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* Address - ns=0;i=14221 */

static UA_StatusCode function_namespace0_generated_235_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Address");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14221LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Address"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21145LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_235_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14221LU));
}

/* NetworkInterface - ns=0;i=17202 */

static UA_StatusCode function_namespace0_generated_236_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NetworkInterface");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17202LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14221LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NetworkInterface"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_236_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17202LU));
}

/* PublishedDataSetType - ns=0;i=14509 */

static UA_StatusCode function_namespace0_generated_237_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedDataSetType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14509LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedDataSetType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_237_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14509LU));
}

/* DataSetClassId - ns=0;i=16759 */

static UA_StatusCode function_namespace0_generated_238_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetClassId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16759LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14509LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetClassId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_238_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16759LU));
}

/* DataSetMetaData - ns=0;i=15229 */

static UA_StatusCode function_namespace0_generated_239_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14523LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetMetaData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15229LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14509LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetMetaData"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_239_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15229LU));
}

/* PublishedDataItemsType - ns=0;i=14534 */

static UA_StatusCode function_namespace0_generated_240_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedDataItemsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14534LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14509LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedDataItemsType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_240_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14534LU));
}

/* RemoveVariables - ns=0;i=14558 */

static UA_StatusCode function_namespace0_generated_241_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveVariables");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14558LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14534LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveVariables"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_241_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14558LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=14560 */

static UA_StatusCode function_namespace0_generated_242_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>NewConfigurationVersion</Name>"
              "<DataType>"
                "<Identifier>i=14593</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>RemoveResults</Name>"
              "<DataType>"
                "<Identifier>i=19</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14560: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14560LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14558LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_242_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14560LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=14559 */

static UA_StatusCode function_namespace0_generated_243_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConfigurationVersion</Name>"
              "<DataType>"
                "<Identifier>i=14593</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>VariablesToRemove</Name>"
              "<DataType>"
                "<Identifier>i=7</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14559: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14559LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14558LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_243_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14559LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddVariables - ns=0;i=14555 */

static UA_StatusCode function_namespace0_generated_244_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddVariables");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14555LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14534LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddVariables"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_244_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14555LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=14557 */

static UA_StatusCode function_namespace0_generated_245_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>NewConfigurationVersion</Name>"
              "<DataType>"
                "<Identifier>i=14593</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>AddResults</Name>"
              "<DataType>"
                "<Identifier>i=19</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14557: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14557LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14555LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_245_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14557LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=14556 */

static UA_StatusCode function_namespace0_generated_246_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConfigurationVersion</Name>"
              "<DataType>"
                "<Identifier>i=14593</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>FieldNameAliases</Name>"
              "<DataType>"
                "<Identifier>i=12</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>PromotedFields</Name>"
              "<DataType>"
                "<Identifier>i=1</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>VariablesToAdd</Name>"
              "<DataType>"
                "<Identifier>i=14273</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14556: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14556LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14555LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_246_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14556LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* PublishedData - ns=0;i=14548 */

static UA_StatusCode function_namespace0_generated_247_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14273LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14548LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14534LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedData"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_247_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14548LU));
}

/* ConfigurationVersion - ns=0;i=14519 */

static UA_StatusCode function_namespace0_generated_248_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14593LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConfigurationVersion");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14519LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14509LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConfigurationVersion"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_248_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14519LU));
}

/* DataSetFolderType - ns=0;i=14477 */

static UA_StatusCode function_namespace0_generated_249_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataSetFolderType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 61LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataSetFolderType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_249_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU));
}

/* RemoveDataSetFolder - ns=0;i=16997 */

static UA_StatusCode function_namespace0_generated_250_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveDataSetFolder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16997LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveDataSetFolder"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_250_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16997LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=17007 */

static UA_StatusCode function_namespace0_generated_251_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetFolderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17007: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17007LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16997LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_251_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17007LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddDataSetFolder - ns=0;i=16994 */

static UA_StatusCode function_namespace0_generated_252_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddDataSetFolder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16994LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddDataSetFolder"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_252_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16994LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=16996 */

static UA_StatusCode function_namespace0_generated_253_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetFolderNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=16996: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16996LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16994LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_253_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16996LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=16995 */

static UA_StatusCode function_namespace0_generated_254_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Name</Name>"
              "<DataType>"
                "<Identifier>i=12</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=16995: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16995LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16994LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_254_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16995LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* RemovePublishedDataSet - ns=0;i=14499 */

static UA_StatusCode function_namespace0_generated_255_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemovePublishedDataSet");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14499LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemovePublishedDataSet"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_255_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14499LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=14500 */

static UA_StatusCode function_namespace0_generated_256_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14500: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14500LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14499LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_256_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14500LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddPublishedDataItems - ns=0;i=14493 */

static UA_StatusCode function_namespace0_generated_257_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddPublishedDataItems");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14493LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddPublishedDataItems"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_257_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14493LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=14495 */

static UA_StatusCode function_namespace0_generated_258_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetNodeId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConfigurationVersion</Name>"
              "<DataType>"
                "<Identifier>i=14593</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>AddResults</Name>"
              "<DataType>"
                "<Identifier>i=19</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14495: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14495LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14493LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_258_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14495LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=14494 */

static UA_StatusCode function_namespace0_generated_259_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Name</Name>"
              "<DataType>"
                "<Identifier>i=12</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>FieldNameAliases</Name>"
              "<DataType>"
                "<Identifier>i=12</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>FieldFlags</Name>"
              "<DataType>"
                "<Identifier>i=15904</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>VariablesToAdd</Name>"
              "<DataType>"
                "<Identifier>i=14273</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14494: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14494LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14493LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_259_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14494LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* <DataSetFolderName> - ns=0;i=14478 */

static UA_StatusCode function_namespace0_generated_260_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<DataSetFolderName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14478LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 35LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<DataSetFolderName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_260_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14478LU));
}

/* PubSubKeyServiceType - ns=0;i=15906 */

static UA_StatusCode function_namespace0_generated_261_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PubSubKeyServiceType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15906LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PubSubKeyServiceType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_261_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15906LU));
}

/* PublishSubscribeType - ns=0;i=14416 */

static UA_StatusCode function_namespace0_generated_262_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishSubscribeType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15906LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishSubscribeType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_262_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU));
}

/* DefaultDatagramPublisherId - ns=0;i=25432 */

static UA_StatusCode function_namespace0_generated_263_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DefaultDatagramPublisherId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25432LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DefaultDatagramPublisherId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_263_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25432LU));
}

/* SubscribedDataSets - ns=0;i=23622 */

static UA_StatusCode function_namespace0_generated_264_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscribedDataSets");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23622LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscribedDataSets"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_264_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23622LU));
}

/* SupportedTransportProfiles - ns=0;i=17479 */

static UA_StatusCode function_namespace0_generated_265_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SupportedTransportProfiles");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17479LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SupportedTransportProfiles"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_265_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17479LU));
}

/* AddConnection - ns=0;i=16598 */

static UA_StatusCode function_namespace0_generated_266_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddConnection");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16598LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddConnection"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_266_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16598LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=16600 */

static UA_StatusCode function_namespace0_generated_267_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConnectionId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=16600: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16600LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16598LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_267_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16600LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=16599 */

static UA_StatusCode function_namespace0_generated_268_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Configuration</Name>"
              "<DataType>"
                "<Identifier>i=15617</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=16599: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16599LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16598LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_268_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16599LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* Status - ns=0;i=15844 */

static UA_StatusCode function_namespace0_generated_269_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Status");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15844LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Status"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14643LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_269_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15844LU));
}

/* State - ns=0;i=15845 */

static UA_StatusCode function_namespace0_generated_270_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14647LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15845LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15844LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_270_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15845LU));
}

/* PublishedDataSets - ns=0;i=14434 */

static UA_StatusCode function_namespace0_generated_271_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedDataSets");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14434LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedDataSets"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_271_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14434LU));
}

/* RemoveConnection - ns=0;i=14432 */

static UA_StatusCode function_namespace0_generated_272_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveConnection");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14432LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveConnection"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_272_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14432LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=14433 */

static UA_StatusCode function_namespace0_generated_273_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConnectionId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=14433: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14433LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14432LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_273_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14433LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* <ConnectionName> - ns=0;i=14417 */

static UA_StatusCode function_namespace0_generated_274_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<ConnectionName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14417LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14476LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<ConnectionName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14209LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_274_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14417LU));
}

/* ConnectionProperties - ns=0;i=17478 */

static UA_StatusCode function_namespace0_generated_275_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14533LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConnectionProperties");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17478LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14417LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConnectionProperties"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_275_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17478LU));
}

/* TransportProfileUri - ns=0;i=17292 */

static UA_StatusCode function_namespace0_generated_276_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProfileUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17292LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14417LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportProfileUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16309LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_276_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17292LU));
}

/* Selections - ns=0;i=17706 */

static UA_StatusCode function_namespace0_generated_277_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Selections");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17706LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17292LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Selections"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_277_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17706LU));
}

/* Address - ns=0;i=14423 */

static UA_StatusCode function_namespace0_generated_278_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Address");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14423LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14417LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Address"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21145LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_278_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14423LU));
}

/* NetworkInterface - ns=0;i=15533 */

static UA_StatusCode function_namespace0_generated_279_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NetworkInterface");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15533LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14423LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NetworkInterface"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_279_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15533LU));
}

/* PublisherId - ns=0;i=14418 */

static UA_StatusCode function_namespace0_generated_280_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublisherId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14418LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14417LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublisherId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_280_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14418LU));
}

/* HistoryServerCapabilitiesType - ns=0;i=2330 */

static UA_StatusCode function_namespace0_generated_281_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryServerCapabilitiesType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2330LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryServerCapabilitiesType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_281_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2330LU));
}

/* ConditionType - ns=0;i=2782 */

static UA_StatusCode function_namespace0_generated_282_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_282_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU));
}

/* AddComment - ns=0;i=9029 */

static UA_StatusCode function_namespace0_generated_283_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddComment");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9029LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddComment"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_283_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9029LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=9030 */

static UA_StatusCode function_namespace0_generated_284_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 2;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>EventId</Name>"
              "<DataType>"
                "<Identifier>i=15</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description>"
                "<Text>The identifier for the event to comment.</Text>"
              "</Description>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Comment</Name>"
              "<DataType>"
                "<Identifier>i=21</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description>"
                "<Text>The comment to add to the condition.</Text>"
              "</Description>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=9030: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9029LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_284_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9030LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* Disable - ns=0;i=9028 */

static UA_StatusCode function_namespace0_generated_285_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Disable");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9028LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Disable"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_285_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9028LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* Enable - ns=0;i=9027 */

static UA_StatusCode function_namespace0_generated_286_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Enable");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9027LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Enable"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_286_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9027LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* ClientUserId - ns=0;i=9026 */

static UA_StatusCode function_namespace0_generated_287_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9026LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_287_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9026LU));
}

/* BranchId - ns=0;i=9010 */

static UA_StatusCode function_namespace0_generated_288_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BranchId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9010LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BranchId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_288_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9010LU));
}

/* ConditionName - ns=0;i=9009 */

static UA_StatusCode function_namespace0_generated_289_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9009LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_289_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9009LU));
}

/* ConditionRefresh - ns=0;i=3875 */

static UA_StatusCode function_namespace0_generated_290_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionRefresh");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3875LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionRefresh"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_290_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3875LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=3876 */

static UA_StatusCode function_namespace0_generated_291_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscriptionId</Name>"
              "<DataType>"
                "<Identifier>i=288</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description>"
                "<Text>The identifier for the subscription to refresh.</Text>"
              "</Description>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=3876: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3876LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3875LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_291_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3876LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* Retain - ns=0;i=3874 */

static UA_StatusCode function_namespace0_generated_292_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Retain");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3874LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Retain"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_292_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3874LU));
}

/* SupportsFilteredRetain - ns=0;i=32060 */

static UA_StatusCode function_namespace0_generated_293_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SupportsFilteredRetain");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 32060LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SupportsFilteredRetain"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_293_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 32060LU));
}

/* ConditionRefresh2 - ns=0;i=12912 */

static UA_StatusCode function_namespace0_generated_294_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionRefresh2");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12912LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionRefresh2"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_294_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12912LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=12913 */

static UA_StatusCode function_namespace0_generated_295_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 2;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscriptionId</Name>"
              "<DataType>"
                "<Identifier>i=288</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description>"
                "<Text>The identifier for the subscription to refresh.</Text>"
              "</Description>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>MonitoredItemId</Name>"
              "<DataType>"
                "<Identifier>i=288</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description>"
                "<Text>The identifier for the monitored item to refresh.</Text>"
              "</Description>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=12913: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12913LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12912LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_295_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12913LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* ConditionClassName - ns=0;i=11113 */

static UA_StatusCode function_namespace0_generated_296_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionClassName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11113LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionClassName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_296_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11113LU));
}

/* ConditionClassId - ns=0;i=11112 */

static UA_StatusCode function_namespace0_generated_297_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionClassId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11112LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionClassId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_297_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11112LU));
}

/* StateVariableType - ns=0;i=2755 */

static UA_StatusCode function_namespace0_generated_298_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "StateVariableType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2755LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "StateVariableType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_298_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2755LU));
}

/* TwoStateVariableType - ns=0;i=8995 */

static UA_StatusCode function_namespace0_generated_299_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TwoStateVariableType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2755LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TwoStateVariableType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_299_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU));
}

/* EnabledState - ns=0;i=9011 */

static UA_StatusCode function_namespace0_generated_300_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnabledState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnabledState"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_300_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU));
}

/* FalseState - ns=0;i=9019 */

static UA_StatusCode function_namespace0_generated_301_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<LocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<Locale>en</Locale>"
        "<Text>Disabled</Text>"
      "</LocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "FalseState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9019LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "FalseState"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_301_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9019LU));
}

/* TrueState - ns=0;i=9018 */

static UA_StatusCode function_namespace0_generated_302_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<LocalizedText xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<Locale>en</Locale>"
        "<Text>Enabled</Text>"
      "</LocalizedText>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "TrueState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9018LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TrueState"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_302_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9018LU));
}

/* EffectiveTransitionTime - ns=0;i=9017 */

static UA_StatusCode function_namespace0_generated_303_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EffectiveTransitionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9017LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EffectiveTransitionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_303_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9017LU));
}

/* TransitionTime - ns=0;i=9016 */

static UA_StatusCode function_namespace0_generated_304_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransitionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9016LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransitionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_304_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9016LU));
}

/* EffectiveDisplayName - ns=0;i=9015 */

static UA_StatusCode function_namespace0_generated_305_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EffectiveDisplayName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9015LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EffectiveDisplayName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_305_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9015LU));
}

/* Id - ns=0;i=9012 */

static UA_StatusCode function_namespace0_generated_306_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Id");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9012LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Id"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_306_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9012LU));
}

/* EffectiveTransitionTime - ns=0;i=9001 */

static UA_StatusCode function_namespace0_generated_307_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EffectiveTransitionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9001LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EffectiveTransitionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_307_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9001LU));
}

/* TransitionTime - ns=0;i=9000 */

static UA_StatusCode function_namespace0_generated_308_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransitionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9000LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransitionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_308_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9000LU));
}

/* Id - ns=0;i=8996 */

static UA_StatusCode function_namespace0_generated_309_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Id");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8996LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Id"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_309_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8996LU));
}

/* FalseState - ns=0;i=11111 */

static UA_StatusCode function_namespace0_generated_310_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "FalseState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11111LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "FalseState"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_310_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11111LU));
}

/* TrueState - ns=0;i=11110 */

static UA_StatusCode function_namespace0_generated_311_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TrueState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11110LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8995LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TrueState"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_311_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11110LU));
}

/* EffectiveDisplayName - ns=0;i=2759 */

static UA_StatusCode function_namespace0_generated_312_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EffectiveDisplayName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2759LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2755LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EffectiveDisplayName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_312_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2759LU));
}

/* Number - ns=0;i=2758 */

static UA_StatusCode function_namespace0_generated_313_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Number");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2758LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2755LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Number"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_313_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2758LU));
}

/* Name - ns=0;i=2757 */

static UA_StatusCode function_namespace0_generated_314_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 20LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Name");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2757LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2755LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Name"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_314_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2757LU));
}

/* Id - ns=0;i=2756 */

static UA_StatusCode function_namespace0_generated_315_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Id");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2756LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2755LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Id"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_315_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2756LU));
}

/* ConditionVariableType - ns=0;i=9002 */

static UA_StatusCode function_namespace0_generated_316_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionVariableType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9002LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionVariableType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_316_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9002LU));
}

/* Comment - ns=0;i=9024 */

static UA_StatusCode function_namespace0_generated_317_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Comment");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9024LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Comment"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9002LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_317_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9024LU));
}

/* SourceTimestamp - ns=0;i=9025 */

static UA_StatusCode function_namespace0_generated_318_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceTimestamp");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9025LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9024LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SourceTimestamp"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_318_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9025LU));
}

/* LastSeverity - ns=0;i=9022 */

static UA_StatusCode function_namespace0_generated_319_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LastSeverity");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9022LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LastSeverity"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9002LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_319_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9022LU));
}

/* SourceTimestamp - ns=0;i=9023 */

static UA_StatusCode function_namespace0_generated_320_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceTimestamp");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9023LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9022LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SourceTimestamp"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_320_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9023LU));
}

/* Quality - ns=0;i=9020 */

static UA_StatusCode function_namespace0_generated_321_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 19LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Quality");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Quality"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9002LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_321_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9020LU));
}

/* SourceTimestamp - ns=0;i=9021 */

static UA_StatusCode function_namespace0_generated_322_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceTimestamp");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SourceTimestamp"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_322_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9021LU));
}

/* SourceTimestamp - ns=0;i=9003 */

static UA_StatusCode function_namespace0_generated_323_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceTimestamp");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9003LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9002LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SourceTimestamp"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_323_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9003LU));
}

/* AuditEventType - ns=0;i=2052 */

static UA_StatusCode function_namespace0_generated_324_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AuditEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuditEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_324_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU));
}

/* AuditUpdateMethodEventType - ns=0;i=2127 */

static UA_StatusCode function_namespace0_generated_325_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AuditUpdateMethodEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2127LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuditUpdateMethodEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_325_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2127LU));
}

/* AuditConditionEventType - ns=0;i=2790 */

static UA_StatusCode function_namespace0_generated_326_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AuditConditionEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2790LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2127LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuditConditionEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_326_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2790LU));
}

/* AuditConditionCommentEventType - ns=0;i=2829 */

static UA_StatusCode function_namespace0_generated_327_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AuditConditionCommentEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2829LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2790LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuditConditionCommentEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2829LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9029LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_327_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2829LU));
}

/* ConditionEventId - ns=0;i=17222 */

static UA_StatusCode function_namespace0_generated_328_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ConditionEventId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17222LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2829LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ConditionEventId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_328_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17222LU));
}

/* Comment - ns=0;i=11851 */

static UA_StatusCode function_namespace0_generated_329_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Comment");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11851LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2829LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Comment"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_329_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11851LU));
}

/* AuditConditionEnableEventType - ns=0;i=2803 */

static UA_StatusCode function_namespace0_generated_330_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AuditConditionEnableEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2803LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2790LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuditConditionEnableEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2803LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9028LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2803LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9027LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_330_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2803LU));
}

/* InputArguments - ns=0;i=2129 */

static UA_StatusCode function_namespace0_generated_331_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2129LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2127LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_331_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2129LU));
}

/* MethodId - ns=0;i=2128 */

static UA_StatusCode function_namespace0_generated_332_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MethodId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2128LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2127LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MethodId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_332_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2128LU));
}

/* ClientUserId - ns=0;i=2057 */

static UA_StatusCode function_namespace0_generated_333_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2057LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_333_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2057LU));
}

/* ClientAuditEntryId - ns=0;i=2056 */

static UA_StatusCode function_namespace0_generated_334_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientAuditEntryId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2056LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientAuditEntryId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_334_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2056LU));
}

/* ServerId - ns=0;i=2055 */

static UA_StatusCode function_namespace0_generated_335_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2055LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_335_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2055LU));
}

/* Status - ns=0;i=2054 */

static UA_StatusCode function_namespace0_generated_336_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Status");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2054LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Status"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_336_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2054LU));
}

/* ActionTimeStamp - ns=0;i=2053 */

static UA_StatusCode function_namespace0_generated_337_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActionTimeStamp");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2053LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2052LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ActionTimeStamp"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_337_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2053LU));
}

/* SystemEventType - ns=0;i=2130 */

static UA_StatusCode function_namespace0_generated_338_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "SystemEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2130LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SystemEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_338_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2130LU));
}

/* RefreshEndEventType - ns=0;i=2788 */

static UA_StatusCode function_namespace0_generated_339_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RefreshEndEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2788LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2130LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RefreshEndEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2788LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3875LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2788LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12912LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_339_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2788LU));
}

/* RefreshStartEventType - ns=0;i=2787 */

static UA_StatusCode function_namespace0_generated_340_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RefreshStartEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2787LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2130LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RefreshStartEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2787LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3875LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2787LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3065LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12912LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_340_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2787LU));
}

/* BaseModelChangeEventType - ns=0;i=2132 */

static UA_StatusCode function_namespace0_generated_341_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "BaseModelChangeEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2132LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BaseModelChangeEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_341_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2132LU));
}

/* GeneralModelChangeEventType - ns=0;i=2133 */

static UA_StatusCode function_namespace0_generated_342_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "GeneralModelChangeEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2133LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2132LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "GeneralModelChangeEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_342_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2133LU));
}

/* Changes - ns=0;i=2134 */

static UA_StatusCode function_namespace0_generated_343_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 877LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Changes");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2134LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2133LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Changes"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_343_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2134LU));
}

/* EventQueueOverflowEventType - ns=0;i=3035 */

static UA_StatusCode function_namespace0_generated_344_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "EventQueueOverflowEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3035LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EventQueueOverflowEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_344_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3035LU));
}

/* Severity - ns=0;i=2051 */

static UA_StatusCode function_namespace0_generated_345_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Severity");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "Indicates how urgent an event is.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2051LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Severity"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_345_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2051LU));
}

/* Message - ns=0;i=2050 */

static UA_StatusCode function_namespace0_generated_346_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Message");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A localized description of the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2050LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Message"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_346_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2050LU));
}

/* LocalTime - ns=0;i=3190 */

static UA_StatusCode function_namespace0_generated_347_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8912LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocalTime");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "Information about the local time where the event originated.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3190LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocalTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_347_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3190LU));
}

/* ReceiveTime - ns=0;i=2047 */

static UA_StatusCode function_namespace0_generated_348_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReceiveTime");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "When the server received the event from the underlying system.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2047LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReceiveTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_348_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2047LU));
}

/* Time - ns=0;i=2046 */

static UA_StatusCode function_namespace0_generated_349_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Time");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "When the event occurred.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2046LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Time"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_349_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2046LU));
}

/* SourceName - ns=0;i=2045 */

static UA_StatusCode function_namespace0_generated_350_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceName");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A description of the source of the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2045LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SourceName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_350_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2045LU));
}

/* SourceNode - ns=0;i=2044 */

static UA_StatusCode function_namespace0_generated_351_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceNode");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "The source of the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2044LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SourceNode"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_351_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2044LU));
}

/* EventType - ns=0;i=2043 */

static UA_StatusCode function_namespace0_generated_352_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventType");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "The identifier for the event type.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2043LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EventType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_352_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2043LU));
}

/* EventId - ns=0;i=2042 */

static UA_StatusCode function_namespace0_generated_353_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventId");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A globally unique identifier for the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2042LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2041LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EventId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_353_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2042LU));
}

/* SessionDiagnosticsVariableType - ns=0;i=2197 */

static UA_StatusCode function_namespace0_generated_354_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsVariableType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnosticsVariableType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_354_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU));
}

/* TotalRequestCount - ns=0;i=8900 */

static UA_StatusCode function_namespace0_generated_355_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8900LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TotalRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_355_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8900LU));
}

/* MaxResponseMessageSize - ns=0;i=3050 */

static UA_StatusCode function_namespace0_generated_356_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3050LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxResponseMessageSize"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_356_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3050LU));
}

/* UnregisterNodesCount - ns=0;i=2731 */

static UA_StatusCode function_namespace0_generated_357_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2731LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnregisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_357_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2731LU));
}

/* RegisterNodesCount - ns=0;i=2730 */

static UA_StatusCode function_namespace0_generated_358_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2730LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RegisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_358_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2730LU));
}

/* QueryNextCount - ns=0;i=2242 */

static UA_StatusCode function_namespace0_generated_359_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2242LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_359_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2242LU));
}

/* QueryFirstCount - ns=0;i=2241 */

static UA_StatusCode function_namespace0_generated_360_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2241LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryFirstCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_360_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2241LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=2240 */

static UA_StatusCode function_namespace0_generated_361_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2240LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_361_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2240LU));
}

/* BrowseNextCount - ns=0;i=2239 */

static UA_StatusCode function_namespace0_generated_362_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2239LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_362_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2239LU));
}

/* BrowseCount - ns=0;i=2238 */

static UA_StatusCode function_namespace0_generated_363_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2238LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_363_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2238LU));
}

/* DeleteReferencesCount - ns=0;i=2237 */

static UA_StatusCode function_namespace0_generated_364_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2237LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_364_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2237LU));
}

/* DeleteNodesCount - ns=0;i=2236 */

static UA_StatusCode function_namespace0_generated_365_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2236LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_365_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2236LU));
}

/* AddReferencesCount - ns=0;i=2235 */

static UA_StatusCode function_namespace0_generated_366_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2235LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_366_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2235LU));
}

/* AddNodesCount - ns=0;i=2234 */

static UA_StatusCode function_namespace0_generated_367_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2234LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_367_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2234LU));
}

/* DeleteSubscriptionsCount - ns=0;i=2233 */

static UA_StatusCode function_namespace0_generated_368_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2233LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_368_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2233LU));
}

/* TransferSubscriptionsCount - ns=0;i=2232 */

static UA_StatusCode function_namespace0_generated_369_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2232LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_369_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2232LU));
}

/* RepublishCount - ns=0;i=2231 */

static UA_StatusCode function_namespace0_generated_370_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2231LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_370_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2231LU));
}

/* PublishCount - ns=0;i=2230 */

static UA_StatusCode function_namespace0_generated_371_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2230LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_371_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2230LU));
}

/* SetPublishingModeCount - ns=0;i=2229 */

static UA_StatusCode function_namespace0_generated_372_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2229LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetPublishingModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_372_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2229LU));
}

/* ModifySubscriptionCount - ns=0;i=2228 */

static UA_StatusCode function_namespace0_generated_373_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2228LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifySubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_373_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2228LU));
}

/* CreateSubscriptionCount - ns=0;i=2227 */

static UA_StatusCode function_namespace0_generated_374_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2227LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_374_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2227LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=2226 */

static UA_StatusCode function_namespace0_generated_375_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2226LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_375_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2226LU));
}

/* SetTriggeringCount - ns=0;i=2225 */

static UA_StatusCode function_namespace0_generated_376_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2225LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetTriggeringCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_376_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2225LU));
}

/* SetMonitoringModeCount - ns=0;i=2224 */

static UA_StatusCode function_namespace0_generated_377_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2224LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetMonitoringModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_377_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2224LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=2223 */

static UA_StatusCode function_namespace0_generated_378_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2223LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_378_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2223LU));
}

/* CreateMonitoredItemsCount - ns=0;i=2222 */

static UA_StatusCode function_namespace0_generated_379_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2222LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_379_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2222LU));
}

/* CallCount - ns=0;i=2221 */

static UA_StatusCode function_namespace0_generated_380_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2221LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CallCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_380_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2221LU));
}

/* HistoryUpdateCount - ns=0;i=2220 */

static UA_StatusCode function_namespace0_generated_381_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2220LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryUpdateCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_381_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2220LU));
}

/* WriteCount - ns=0;i=2219 */

static UA_StatusCode function_namespace0_generated_382_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2219LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriteCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_382_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2219LU));
}

/* HistoryReadCount - ns=0;i=2218 */

static UA_StatusCode function_namespace0_generated_383_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2218LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_383_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2218LU));
}

/* ReadCount - ns=0;i=2217 */

static UA_StatusCode function_namespace0_generated_384_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2217LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_384_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2217LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=2209 */

static UA_StatusCode function_namespace0_generated_385_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2209LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_385_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2209LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=2208 */

static UA_StatusCode function_namespace0_generated_386_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2208LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_386_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2208LU));
}

/* CurrentSubscriptionsCount - ns=0;i=2207 */

static UA_StatusCode function_namespace0_generated_387_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2207LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_387_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2207LU));
}

/* ClientLastContactTime - ns=0;i=2206 */

static UA_StatusCode function_namespace0_generated_388_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2206LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientLastContactTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_388_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2206LU));
}

/* ClientConnectionTime - ns=0;i=2205 */

static UA_StatusCode function_namespace0_generated_389_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2205LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientConnectionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_389_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2205LU));
}

/* ActualSessionTimeout - ns=0;i=2204 */

static UA_StatusCode function_namespace0_generated_390_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2204LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ActualSessionTimeout"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_390_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2204LU));
}

/* LocaleIds - ns=0;i=2203 */

static UA_StatusCode function_namespace0_generated_391_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2203LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocaleIds"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_391_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2203LU));
}

/* EndpointUrl - ns=0;i=2202 */

static UA_StatusCode function_namespace0_generated_392_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2202LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EndpointUrl"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_392_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2202LU));
}

/* ServerUri - ns=0;i=2201 */

static UA_StatusCode function_namespace0_generated_393_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2201LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_393_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2201LU));
}

/* ClientDescription - ns=0;i=2200 */

static UA_StatusCode function_namespace0_generated_394_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2200LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientDescription"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_394_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2200LU));
}

/* SessionName - ns=0;i=2199 */

static UA_StatusCode function_namespace0_generated_395_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2199LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_395_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2199LU));
}

/* SessionId - ns=0;i=2198 */

static UA_StatusCode function_namespace0_generated_396_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2198LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_396_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2198LU));
}

/* UnauthorizedRequestCount - ns=0;i=11892 */

static UA_StatusCode function_namespace0_generated_397_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11892LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_397_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11892LU));
}

/* SubscriptionDiagnosticsType - ns=0;i=2172 */

static UA_StatusCode function_namespace0_generated_398_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnosticsType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_398_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU));
}

/* EventQueueOverflowCount - ns=0;i=8902 */

static UA_StatusCode function_namespace0_generated_399_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8902LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EventQueueOverflowCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_399_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8902LU));
}

/* NextSequenceNumber - ns=0;i=8897 */

static UA_StatusCode function_namespace0_generated_400_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NextSequenceNumber");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8897LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NextSequenceNumber"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_400_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8897LU));
}

/* MonitoringQueueOverflowCount - ns=0;i=8896 */

static UA_StatusCode function_namespace0_generated_401_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoringQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8896LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MonitoringQueueOverflowCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_401_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8896LU));
}

/* DisabledMonitoredItemCount - ns=0;i=8895 */

static UA_StatusCode function_namespace0_generated_402_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8895LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DisabledMonitoredItemCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_402_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8895LU));
}

/* MonitoredItemCount - ns=0;i=8894 */

static UA_StatusCode function_namespace0_generated_403_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8894LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MonitoredItemCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_403_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8894LU));
}

/* DiscardedMessageCount - ns=0;i=8893 */

static UA_StatusCode function_namespace0_generated_404_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DiscardedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8893LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DiscardedMessageCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_404_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8893LU));
}

/* UnacknowledgedMessageCount - ns=0;i=8892 */

static UA_StatusCode function_namespace0_generated_405_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnacknowledgedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8892LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnacknowledgedMessageCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_405_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8892LU));
}

/* CurrentLifetimeCount - ns=0;i=8891 */

static UA_StatusCode function_namespace0_generated_406_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8891LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentLifetimeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_406_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8891LU));
}

/* CurrentKeepAliveCount - ns=0;i=8890 */

static UA_StatusCode function_namespace0_generated_407_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8890LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentKeepAliveCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_407_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8890LU));
}

/* LatePublishRequestCount - ns=0;i=8889 */

static UA_StatusCode function_namespace0_generated_408_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LatePublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8889LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LatePublishRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_408_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8889LU));
}

/* MaxLifetimeCount - ns=0;i=8888 */

static UA_StatusCode function_namespace0_generated_409_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8888LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxLifetimeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_409_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8888LU));
}

/* EventNotificationsCount - ns=0;i=2998 */

static UA_StatusCode function_namespace0_generated_410_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2998LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EventNotificationsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_410_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2998LU));
}

/* NotificationsCount - ns=0;i=2193 */

static UA_StatusCode function_namespace0_generated_411_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2193LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NotificationsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_411_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2193LU));
}

/* DataChangeNotificationsCount - ns=0;i=2191 */

static UA_StatusCode function_namespace0_generated_412_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataChangeNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2191LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataChangeNotificationsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_412_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2191LU));
}

/* PublishRequestCount - ns=0;i=2190 */

static UA_StatusCode function_namespace0_generated_413_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2190LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_413_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2190LU));
}

/* TransferredToSameClientCount - ns=0;i=2189 */

static UA_StatusCode function_namespace0_generated_414_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToSameClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2189LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferredToSameClientCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_414_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2189LU));
}

/* TransferredToAltClientCount - ns=0;i=2188 */

static UA_StatusCode function_namespace0_generated_415_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToAltClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2188LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferredToAltClientCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_415_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2188LU));
}

/* TransferRequestCount - ns=0;i=2187 */

static UA_StatusCode function_namespace0_generated_416_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2187LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_416_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2187LU));
}

/* RepublishMessageCount - ns=0;i=2186 */

static UA_StatusCode function_namespace0_generated_417_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2186LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishMessageCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_417_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2186LU));
}

/* RepublishMessageRequestCount - ns=0;i=2185 */

static UA_StatusCode function_namespace0_generated_418_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2185LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishMessageRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_418_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2185LU));
}

/* RepublishRequestCount - ns=0;i=2184 */

static UA_StatusCode function_namespace0_generated_419_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2184LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_419_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2184LU));
}

/* DisableCount - ns=0;i=2183 */

static UA_StatusCode function_namespace0_generated_420_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2183LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DisableCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_420_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2183LU));
}

/* EnableCount - ns=0;i=2182 */

static UA_StatusCode function_namespace0_generated_421_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2182LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnableCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_421_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2182LU));
}

/* ModifyCount - ns=0;i=2181 */

static UA_StatusCode function_namespace0_generated_422_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2181LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifyCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_422_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2181LU));
}

/* PublishingEnabled - ns=0;i=2180 */

static UA_StatusCode function_namespace0_generated_423_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingEnabled");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2180LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingEnabled"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_423_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2180LU));
}

/* MaxNotificationsPerPublish - ns=0;i=2179 */

static UA_StatusCode function_namespace0_generated_424_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNotificationsPerPublish");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2179LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNotificationsPerPublish"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_424_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2179LU));
}

/* MaxKeepAliveCount - ns=0;i=2177 */

static UA_StatusCode function_namespace0_generated_425_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2177LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxKeepAliveCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_425_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2177LU));
}

/* PublishingInterval - ns=0;i=2176 */

static UA_StatusCode function_namespace0_generated_426_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2176LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingInterval"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_426_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2176LU));
}

/* Priority - ns=0;i=2175 */

static UA_StatusCode function_namespace0_generated_427_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Priority");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2175LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Priority"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_427_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2175LU));
}

/* SubscriptionId - ns=0;i=2174 */

static UA_StatusCode function_namespace0_generated_428_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2174LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_428_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2174LU));
}

/* SessionId - ns=0;i=2173 */

static UA_StatusCode function_namespace0_generated_429_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2173LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_429_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2173LU));
}

/* SubscriptionDiagnosticsArrayType - ns=0;i=2171 */

static UA_StatusCode function_namespace0_generated_430_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2171LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnosticsArrayType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_430_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2171LU));
}

/* SubscriptionDiagnostics - ns=0;i=12784 */

static UA_StatusCode function_namespace0_generated_431_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2171LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2172LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_431_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU));
}

/* EventQueueOverflowCount - ns=0;i=12815 */

static UA_StatusCode function_namespace0_generated_432_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12815LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EventQueueOverflowCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_432_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12815LU));
}

/* NextSequenceNumber - ns=0;i=12814 */

static UA_StatusCode function_namespace0_generated_433_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NextSequenceNumber");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12814LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NextSequenceNumber"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_433_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12814LU));
}

/* MonitoringQueueOverflowCount - ns=0;i=12813 */

static UA_StatusCode function_namespace0_generated_434_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoringQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12813LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MonitoringQueueOverflowCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_434_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12813LU));
}

/* DisabledMonitoredItemCount - ns=0;i=12812 */

static UA_StatusCode function_namespace0_generated_435_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12812LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DisabledMonitoredItemCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_435_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12812LU));
}

/* MonitoredItemCount - ns=0;i=12811 */

static UA_StatusCode function_namespace0_generated_436_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12811LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MonitoredItemCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_436_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12811LU));
}

/* DiscardedMessageCount - ns=0;i=12810 */

static UA_StatusCode function_namespace0_generated_437_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DiscardedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12810LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DiscardedMessageCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_437_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12810LU));
}

/* UnacknowledgedMessageCount - ns=0;i=12809 */

static UA_StatusCode function_namespace0_generated_438_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnacknowledgedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12809LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnacknowledgedMessageCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_438_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12809LU));
}

/* CurrentLifetimeCount - ns=0;i=12808 */

static UA_StatusCode function_namespace0_generated_439_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12808LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentLifetimeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_439_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12808LU));
}

/* CurrentKeepAliveCount - ns=0;i=12807 */

static UA_StatusCode function_namespace0_generated_440_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12807LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentKeepAliveCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_440_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12807LU));
}

/* LatePublishRequestCount - ns=0;i=12806 */

static UA_StatusCode function_namespace0_generated_441_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LatePublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12806LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LatePublishRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_441_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12806LU));
}

/* NotificationsCount - ns=0;i=12805 */

static UA_StatusCode function_namespace0_generated_442_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12805LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NotificationsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_442_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12805LU));
}

/* EventNotificationsCount - ns=0;i=12804 */

static UA_StatusCode function_namespace0_generated_443_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12804LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EventNotificationsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_443_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12804LU));
}

/* DataChangeNotificationsCount - ns=0;i=12803 */

static UA_StatusCode function_namespace0_generated_444_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataChangeNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12803LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataChangeNotificationsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_444_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12803LU));
}

/* PublishRequestCount - ns=0;i=12802 */

static UA_StatusCode function_namespace0_generated_445_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12802LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_445_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12802LU));
}

/* TransferredToSameClientCount - ns=0;i=12801 */

static UA_StatusCode function_namespace0_generated_446_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToSameClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12801LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferredToSameClientCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_446_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12801LU));
}

/* TransferredToAltClientCount - ns=0;i=12800 */

static UA_StatusCode function_namespace0_generated_447_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToAltClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12800LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferredToAltClientCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_447_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12800LU));
}

/* TransferRequestCount - ns=0;i=12799 */

static UA_StatusCode function_namespace0_generated_448_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12799LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_448_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12799LU));
}

/* RepublishMessageCount - ns=0;i=12798 */

static UA_StatusCode function_namespace0_generated_449_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12798LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishMessageCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_449_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12798LU));
}

/* RepublishMessageRequestCount - ns=0;i=12797 */

static UA_StatusCode function_namespace0_generated_450_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12797LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishMessageRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_450_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12797LU));
}

/* RepublishRequestCount - ns=0;i=12796 */

static UA_StatusCode function_namespace0_generated_451_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12796LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_451_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12796LU));
}

/* DisableCount - ns=0;i=12795 */

static UA_StatusCode function_namespace0_generated_452_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12795LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DisableCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_452_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12795LU));
}

/* EnableCount - ns=0;i=12794 */

static UA_StatusCode function_namespace0_generated_453_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12794LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnableCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_453_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12794LU));
}

/* ModifyCount - ns=0;i=12793 */

static UA_StatusCode function_namespace0_generated_454_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12793LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifyCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_454_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12793LU));
}

/* PublishingEnabled - ns=0;i=12792 */

static UA_StatusCode function_namespace0_generated_455_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingEnabled");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12792LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingEnabled"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_455_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12792LU));
}

/* MaxNotificationsPerPublish - ns=0;i=12791 */

static UA_StatusCode function_namespace0_generated_456_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNotificationsPerPublish");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12791LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNotificationsPerPublish"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_456_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12791LU));
}

/* MaxLifetimeCount - ns=0;i=12790 */

static UA_StatusCode function_namespace0_generated_457_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12790LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxLifetimeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_457_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12790LU));
}

/* MaxKeepAliveCount - ns=0;i=12789 */

static UA_StatusCode function_namespace0_generated_458_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12789LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxKeepAliveCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_458_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12789LU));
}

/* PublishingInterval - ns=0;i=12788 */

static UA_StatusCode function_namespace0_generated_459_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12788LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingInterval"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_459_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12788LU));
}

/* Priority - ns=0;i=12787 */

static UA_StatusCode function_namespace0_generated_460_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Priority");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12787LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Priority"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_460_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12787LU));
}

/* SubscriptionId - ns=0;i=12786 */

static UA_StatusCode function_namespace0_generated_461_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12786LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_461_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12786LU));
}

/* SessionId - ns=0;i=12785 */

static UA_StatusCode function_namespace0_generated_462_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12785LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_462_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12785LU));
}

/* SessionSecurityDiagnosticsType - ns=0;i=2244 */

static UA_StatusCode function_namespace0_generated_463_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnosticsType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_463_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU));
}

/* ClientCertificate - ns=0;i=3058 */

static UA_StatusCode function_namespace0_generated_464_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3058LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientCertificate"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_464_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3058LU));
}

/* SecurityPolicyUri - ns=0;i=2252 */

static UA_StatusCode function_namespace0_generated_465_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2252LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityPolicyUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_465_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2252LU));
}

/* SecurityMode - ns=0;i=2251 */

static UA_StatusCode function_namespace0_generated_466_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2251LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityMode"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_466_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2251LU));
}

/* TransportProtocol - ns=0;i=2250 */

static UA_StatusCode function_namespace0_generated_467_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2250LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportProtocol"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_467_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2250LU));
}

/* Encoding - ns=0;i=2249 */

static UA_StatusCode function_namespace0_generated_468_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2249LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Encoding"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_468_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2249LU));
}

/* AuthenticationMechanism - ns=0;i=2248 */

static UA_StatusCode function_namespace0_generated_469_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2248LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuthenticationMechanism"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_469_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2248LU));
}

/* ClientUserIdHistory - ns=0;i=2247 */

static UA_StatusCode function_namespace0_generated_470_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2247LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdHistory"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_470_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2247LU));
}

/* ClientUserIdOfSession - ns=0;i=2246 */

static UA_StatusCode function_namespace0_generated_471_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2246LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdOfSession"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_471_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2246LU));
}

/* SessionId - ns=0;i=2245 */

static UA_StatusCode function_namespace0_generated_472_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2245LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_472_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2245LU));
}

/* SessionDiagnosticsObjectType - ns=0;i=2029 */

static UA_StatusCode function_namespace0_generated_473_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsObjectType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2029LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnosticsObjectType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_473_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2029LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=2032 */

static UA_StatusCode function_namespace0_generated_474_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2032LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2029LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_474_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2032LU));
}

/* SessionSecurityDiagnostics - ns=0;i=2031 */

static UA_StatusCode function_namespace0_generated_475_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2029LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_475_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU));
}

/* ClientCertificate - ns=0;i=3187 */

static UA_StatusCode function_namespace0_generated_476_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3187LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientCertificate"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_476_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3187LU));
}

/* SecurityPolicyUri - ns=0;i=3186 */

static UA_StatusCode function_namespace0_generated_477_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3186LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityPolicyUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_477_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3186LU));
}

/* SecurityMode - ns=0;i=3185 */

static UA_StatusCode function_namespace0_generated_478_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3185LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityMode"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_478_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3185LU));
}

/* TransportProtocol - ns=0;i=3184 */

static UA_StatusCode function_namespace0_generated_479_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3184LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportProtocol"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_479_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3184LU));
}

/* Encoding - ns=0;i=3183 */

static UA_StatusCode function_namespace0_generated_480_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3183LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Encoding"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_480_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3183LU));
}

/* AuthenticationMechanism - ns=0;i=3182 */

static UA_StatusCode function_namespace0_generated_481_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3182LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuthenticationMechanism"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_481_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3182LU));
}

/* ClientUserIdHistory - ns=0;i=3181 */

static UA_StatusCode function_namespace0_generated_482_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3181LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdHistory"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_482_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3181LU));
}

/* ClientUserIdOfSession - ns=0;i=3180 */

static UA_StatusCode function_namespace0_generated_483_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3180LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdOfSession"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_483_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3180LU));
}

/* SessionId - ns=0;i=3179 */

static UA_StatusCode function_namespace0_generated_484_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3179LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_484_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3179LU));
}

/* SessionDiagnostics - ns=0;i=2030 */

static UA_StatusCode function_namespace0_generated_485_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2029LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_485_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU));
}

/* TotalRequestCount - ns=0;i=8898 */

static UA_StatusCode function_namespace0_generated_486_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8898LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TotalRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_486_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8898LU));
}

/* UnregisterNodesCount - ns=0;i=3178 */

static UA_StatusCode function_namespace0_generated_487_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3178LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnregisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_487_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3178LU));
}

/* RegisterNodesCount - ns=0;i=3177 */

static UA_StatusCode function_namespace0_generated_488_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3177LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RegisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_488_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3177LU));
}

/* QueryNextCount - ns=0;i=3176 */

static UA_StatusCode function_namespace0_generated_489_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3176LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_489_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3176LU));
}

/* QueryFirstCount - ns=0;i=3175 */

static UA_StatusCode function_namespace0_generated_490_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3175LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryFirstCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_490_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3175LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=3174 */

static UA_StatusCode function_namespace0_generated_491_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3174LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_491_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3174LU));
}

/* BrowseNextCount - ns=0;i=3173 */

static UA_StatusCode function_namespace0_generated_492_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3173LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_492_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3173LU));
}

/* BrowseCount - ns=0;i=3172 */

static UA_StatusCode function_namespace0_generated_493_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3172LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_493_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3172LU));
}

/* DeleteReferencesCount - ns=0;i=3171 */

static UA_StatusCode function_namespace0_generated_494_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3171LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_494_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3171LU));
}

/* DeleteNodesCount - ns=0;i=3170 */

static UA_StatusCode function_namespace0_generated_495_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3170LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_495_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3170LU));
}

/* AddReferencesCount - ns=0;i=3169 */

static UA_StatusCode function_namespace0_generated_496_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3169LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_496_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3169LU));
}

/* AddNodesCount - ns=0;i=3168 */

static UA_StatusCode function_namespace0_generated_497_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3168LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_497_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3168LU));
}

/* DeleteSubscriptionsCount - ns=0;i=3167 */

static UA_StatusCode function_namespace0_generated_498_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3167LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_498_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3167LU));
}

/* TransferSubscriptionsCount - ns=0;i=3166 */

static UA_StatusCode function_namespace0_generated_499_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3166LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_499_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3166LU));
}

/* RepublishCount - ns=0;i=3165 */

static UA_StatusCode function_namespace0_generated_500_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3165LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_500_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3165LU));
}

/* PublishCount - ns=0;i=3164 */

static UA_StatusCode function_namespace0_generated_501_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3164LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_501_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3164LU));
}

/* SetPublishingModeCount - ns=0;i=3163 */

static UA_StatusCode function_namespace0_generated_502_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3163LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetPublishingModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_502_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3163LU));
}

/* ModifySubscriptionCount - ns=0;i=3162 */

static UA_StatusCode function_namespace0_generated_503_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3162LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifySubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_503_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3162LU));
}

/* CreateSubscriptionCount - ns=0;i=3161 */

static UA_StatusCode function_namespace0_generated_504_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3161LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_504_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3161LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=3160 */

static UA_StatusCode function_namespace0_generated_505_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3160LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_505_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3160LU));
}

/* SetTriggeringCount - ns=0;i=3159 */

static UA_StatusCode function_namespace0_generated_506_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3159LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetTriggeringCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_506_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3159LU));
}

/* SetMonitoringModeCount - ns=0;i=3158 */

static UA_StatusCode function_namespace0_generated_507_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3158LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetMonitoringModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_507_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3158LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=3157 */

static UA_StatusCode function_namespace0_generated_508_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3157LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_508_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3157LU));
}

/* CreateMonitoredItemsCount - ns=0;i=3156 */

static UA_StatusCode function_namespace0_generated_509_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3156LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_509_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3156LU));
}

/* CallCount - ns=0;i=3155 */

static UA_StatusCode function_namespace0_generated_510_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3155LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CallCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_510_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3155LU));
}

/* HistoryUpdateCount - ns=0;i=3154 */

static UA_StatusCode function_namespace0_generated_511_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3154LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryUpdateCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_511_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3154LU));
}

/* WriteCount - ns=0;i=3153 */

static UA_StatusCode function_namespace0_generated_512_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3153LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriteCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_512_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3153LU));
}

/* HistoryReadCount - ns=0;i=3152 */

static UA_StatusCode function_namespace0_generated_513_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3152LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_513_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3152LU));
}

/* ReadCount - ns=0;i=3151 */

static UA_StatusCode function_namespace0_generated_514_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3151LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_514_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3151LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=3143 */

static UA_StatusCode function_namespace0_generated_515_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3143LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_515_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3143LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=3142 */

static UA_StatusCode function_namespace0_generated_516_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_516_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3142LU));
}

/* CurrentSubscriptionsCount - ns=0;i=3141 */

static UA_StatusCode function_namespace0_generated_517_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3141LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_517_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3141LU));
}

/* ClientLastContactTime - ns=0;i=3140 */

static UA_StatusCode function_namespace0_generated_518_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3140LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientLastContactTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_518_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3140LU));
}

/* ClientConnectionTime - ns=0;i=3139 */

static UA_StatusCode function_namespace0_generated_519_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3139LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientConnectionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_519_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3139LU));
}

/* MaxResponseMessageSize - ns=0;i=3138 */

static UA_StatusCode function_namespace0_generated_520_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3138LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxResponseMessageSize"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_520_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3138LU));
}

/* ActualSessionTimeout - ns=0;i=3137 */

static UA_StatusCode function_namespace0_generated_521_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3137LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ActualSessionTimeout"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_521_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3137LU));
}

/* LocaleIds - ns=0;i=3136 */

static UA_StatusCode function_namespace0_generated_522_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3136LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocaleIds"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_522_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3136LU));
}

/* EndpointUrl - ns=0;i=3135 */

static UA_StatusCode function_namespace0_generated_523_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3135LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EndpointUrl"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_523_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3135LU));
}

/* ServerUri - ns=0;i=3134 */

static UA_StatusCode function_namespace0_generated_524_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3134LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_524_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3134LU));
}

/* ClientDescription - ns=0;i=3133 */

static UA_StatusCode function_namespace0_generated_525_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3133LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientDescription"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_525_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3133LU));
}

/* SessionName - ns=0;i=3132 */

static UA_StatusCode function_namespace0_generated_526_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3132LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_526_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3132LU));
}

/* SessionId - ns=0;i=3131 */

static UA_StatusCode function_namespace0_generated_527_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3131LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_527_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3131LU));
}

/* UnauthorizedRequestCount - ns=0;i=11891 */

static UA_StatusCode function_namespace0_generated_528_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11891LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_528_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11891LU));
}

/* ServerDiagnosticsSummaryType - ns=0;i=2150 */

static UA_StatusCode function_namespace0_generated_529_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 859LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummaryType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerDiagnosticsSummaryType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_529_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU));
}

/* RejectedRequestsCount - ns=0;i=2163 */

static UA_StatusCode function_namespace0_generated_530_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2163LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RejectedRequestsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_530_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2163LU));
}

/* SecurityRejectedRequestsCount - ns=0;i=2162 */

static UA_StatusCode function_namespace0_generated_531_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2162LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityRejectedRequestsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_531_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2162LU));
}

/* CumulatedSubscriptionCount - ns=0;i=2161 */

static UA_StatusCode function_namespace0_generated_532_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2161LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CumulatedSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_532_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2161LU));
}

/* CurrentSubscriptionCount - ns=0;i=2160 */

static UA_StatusCode function_namespace0_generated_533_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2160LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_533_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2160LU));
}

/* PublishingIntervalCount - ns=0;i=2159 */

static UA_StatusCode function_namespace0_generated_534_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2159LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingIntervalCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_534_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2159LU));
}

/* SessionAbortCount - ns=0;i=2157 */

static UA_StatusCode function_namespace0_generated_535_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2157LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionAbortCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_535_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2157LU));
}

/* SessionTimeoutCount - ns=0;i=2156 */

static UA_StatusCode function_namespace0_generated_536_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2156LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionTimeoutCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_536_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2156LU));
}

/* RejectedSessionCount - ns=0;i=2155 */

static UA_StatusCode function_namespace0_generated_537_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2155LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RejectedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_537_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2155LU));
}

/* SecurityRejectedSessionCount - ns=0;i=2154 */

static UA_StatusCode function_namespace0_generated_538_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2154LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityRejectedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_538_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2154LU));
}

/* CumulatedSessionCount - ns=0;i=2153 */

static UA_StatusCode function_namespace0_generated_539_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2153LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CumulatedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_539_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2153LU));
}

/* CurrentSessionCount - ns=0;i=2152 */

static UA_StatusCode function_namespace0_generated_540_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2152LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_540_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2152LU));
}

/* ServerViewCount - ns=0;i=2151 */

static UA_StatusCode function_namespace0_generated_541_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2151LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerViewCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_541_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2151LU));
}

/* SamplingIntervalDiagnosticsType - ns=0;i=2165 */

static UA_StatusCode function_namespace0_generated_542_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2165LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SamplingIntervalDiagnosticsType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_542_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2165LU));
}

/* SamplingInterval - ns=0;i=2166 */

static UA_StatusCode function_namespace0_generated_543_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2166LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2165LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SamplingInterval"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_543_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2166LU));
}

/* DisabledMonitoredItemsSamplingCount - ns=0;i=11699 */

static UA_StatusCode function_namespace0_generated_544_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemsSamplingCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11699LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2165LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DisabledMonitoredItemsSamplingCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_544_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11699LU));
}

/* MaxSampledMonitoredItemsCount - ns=0;i=11698 */

static UA_StatusCode function_namespace0_generated_545_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxSampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11698LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2165LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxSampledMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_545_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11698LU));
}

/* SampledMonitoredItemsCount - ns=0;i=11697 */

static UA_StatusCode function_namespace0_generated_546_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11697LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2165LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SampledMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_546_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11697LU));
}

/* SamplingIntervalDiagnosticsArrayType - ns=0;i=2164 */

static UA_StatusCode function_namespace0_generated_547_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2164LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SamplingIntervalDiagnosticsArrayType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_547_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2164LU));
}

/* SamplingIntervalDiagnostics - ns=0;i=12779 */

static UA_StatusCode function_namespace0_generated_548_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12779LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2164LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SamplingIntervalDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2165LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_548_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12779LU));
}

/* DisabledMonitoredItemsSamplingCount - ns=0;i=12783 */

static UA_StatusCode function_namespace0_generated_549_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemsSamplingCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12783LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12779LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DisabledMonitoredItemsSamplingCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_549_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12783LU));
}

/* MaxSampledMonitoredItemsCount - ns=0;i=12782 */

static UA_StatusCode function_namespace0_generated_550_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxSampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12782LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12779LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxSampledMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_550_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12782LU));
}

/* SampledMonitoredItemsCount - ns=0;i=12781 */

static UA_StatusCode function_namespace0_generated_551_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12781LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12779LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SampledMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_551_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12781LU));
}

/* SamplingInterval - ns=0;i=12780 */

static UA_StatusCode function_namespace0_generated_552_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12780LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12779LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SamplingInterval"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_552_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12780LU));
}

/* SessionDiagnosticsArrayType - ns=0;i=2196 */

static UA_StatusCode function_namespace0_generated_553_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2196LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnosticsArrayType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_553_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2196LU));
}

/* SessionDiagnostics - ns=0;i=12816 */

static UA_StatusCode function_namespace0_generated_554_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2196LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_554_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU));
}

/* UnregisterNodesCount - ns=0;i=12859 */

static UA_StatusCode function_namespace0_generated_555_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12859LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnregisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_555_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12859LU));
}

/* RegisterNodesCount - ns=0;i=12858 */

static UA_StatusCode function_namespace0_generated_556_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12858LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RegisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_556_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12858LU));
}

/* QueryNextCount - ns=0;i=12857 */

static UA_StatusCode function_namespace0_generated_557_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12857LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_557_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12857LU));
}

/* QueryFirstCount - ns=0;i=12856 */

static UA_StatusCode function_namespace0_generated_558_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12856LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryFirstCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_558_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12856LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=12855 */

static UA_StatusCode function_namespace0_generated_559_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12855LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_559_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12855LU));
}

/* BrowseNextCount - ns=0;i=12854 */

static UA_StatusCode function_namespace0_generated_560_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12854LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_560_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12854LU));
}

/* BrowseCount - ns=0;i=12853 */

static UA_StatusCode function_namespace0_generated_561_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12853LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_561_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12853LU));
}

/* DeleteReferencesCount - ns=0;i=12852 */

static UA_StatusCode function_namespace0_generated_562_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12852LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_562_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12852LU));
}

/* DeleteNodesCount - ns=0;i=12851 */

static UA_StatusCode function_namespace0_generated_563_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12851LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_563_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12851LU));
}

/* AddReferencesCount - ns=0;i=12850 */

static UA_StatusCode function_namespace0_generated_564_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12850LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_564_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12850LU));
}

/* AddNodesCount - ns=0;i=12849 */

static UA_StatusCode function_namespace0_generated_565_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12849LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_565_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12849LU));
}

/* DeleteSubscriptionsCount - ns=0;i=12848 */

static UA_StatusCode function_namespace0_generated_566_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12848LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_566_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12848LU));
}

/* TransferSubscriptionsCount - ns=0;i=12847 */

static UA_StatusCode function_namespace0_generated_567_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12847LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_567_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12847LU));
}

/* RepublishCount - ns=0;i=12846 */

static UA_StatusCode function_namespace0_generated_568_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12846LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_568_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12846LU));
}

/* PublishCount - ns=0;i=12845 */

static UA_StatusCode function_namespace0_generated_569_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12845LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_569_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12845LU));
}

/* SetPublishingModeCount - ns=0;i=12844 */

static UA_StatusCode function_namespace0_generated_570_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12844LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetPublishingModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_570_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12844LU));
}

/* ModifySubscriptionCount - ns=0;i=12843 */

static UA_StatusCode function_namespace0_generated_571_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12843LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifySubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_571_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12843LU));
}

/* CreateSubscriptionCount - ns=0;i=12842 */

static UA_StatusCode function_namespace0_generated_572_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12842LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_572_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12842LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=12841 */

static UA_StatusCode function_namespace0_generated_573_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12841LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_573_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12841LU));
}

/* SetTriggeringCount - ns=0;i=12840 */

static UA_StatusCode function_namespace0_generated_574_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12840LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetTriggeringCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_574_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12840LU));
}

/* SetMonitoringModeCount - ns=0;i=12839 */

static UA_StatusCode function_namespace0_generated_575_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12839LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetMonitoringModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_575_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12839LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=12838 */

static UA_StatusCode function_namespace0_generated_576_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12838LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_576_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12838LU));
}

/* CreateMonitoredItemsCount - ns=0;i=12837 */

static UA_StatusCode function_namespace0_generated_577_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12837LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_577_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12837LU));
}

/* CallCount - ns=0;i=12836 */

static UA_StatusCode function_namespace0_generated_578_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12836LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CallCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_578_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12836LU));
}

/* HistoryUpdateCount - ns=0;i=12835 */

static UA_StatusCode function_namespace0_generated_579_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12835LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryUpdateCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_579_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12835LU));
}

/* WriteCount - ns=0;i=12834 */

static UA_StatusCode function_namespace0_generated_580_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12834LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriteCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_580_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12834LU));
}

/* HistoryReadCount - ns=0;i=12833 */

static UA_StatusCode function_namespace0_generated_581_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12833LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_581_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12833LU));
}

/* ReadCount - ns=0;i=12832 */

static UA_StatusCode function_namespace0_generated_582_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12832LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_582_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12832LU));
}

/* UnauthorizedRequestCount - ns=0;i=12831 */

static UA_StatusCode function_namespace0_generated_583_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12831LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_583_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12831LU));
}

/* TotalRequestCount - ns=0;i=12830 */

static UA_StatusCode function_namespace0_generated_584_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12830LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TotalRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_584_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12830LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=12829 */

static UA_StatusCode function_namespace0_generated_585_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12829LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_585_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12829LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=12828 */

static UA_StatusCode function_namespace0_generated_586_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12828LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_586_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12828LU));
}

/* CurrentSubscriptionsCount - ns=0;i=12827 */

static UA_StatusCode function_namespace0_generated_587_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12827LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_587_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12827LU));
}

/* ClientLastContactTime - ns=0;i=12826 */

static UA_StatusCode function_namespace0_generated_588_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12826LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientLastContactTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_588_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12826LU));
}

/* ClientConnectionTime - ns=0;i=12825 */

static UA_StatusCode function_namespace0_generated_589_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12825LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientConnectionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_589_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12825LU));
}

/* MaxResponseMessageSize - ns=0;i=12824 */

static UA_StatusCode function_namespace0_generated_590_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12824LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxResponseMessageSize"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_590_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12824LU));
}

/* ActualSessionTimeout - ns=0;i=12823 */

static UA_StatusCode function_namespace0_generated_591_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12823LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ActualSessionTimeout"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_591_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12823LU));
}

/* LocaleIds - ns=0;i=12822 */

static UA_StatusCode function_namespace0_generated_592_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12822LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocaleIds"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_592_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12822LU));
}

/* EndpointUrl - ns=0;i=12821 */

static UA_StatusCode function_namespace0_generated_593_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12821LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EndpointUrl"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_593_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12821LU));
}

/* ServerUri - ns=0;i=12820 */

static UA_StatusCode function_namespace0_generated_594_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12820LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_594_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12820LU));
}

/* ClientDescription - ns=0;i=12819 */

static UA_StatusCode function_namespace0_generated_595_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12819LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientDescription"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_595_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12819LU));
}

/* SessionName - ns=0;i=12818 */

static UA_StatusCode function_namespace0_generated_596_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12818LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_596_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12818LU));
}

/* SessionId - ns=0;i=12817 */

static UA_StatusCode function_namespace0_generated_597_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12817LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_597_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12817LU));
}

/* SessionSecurityDiagnosticsArrayType - ns=0;i=2243 */

static UA_StatusCode function_namespace0_generated_598_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2243LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnosticsArrayType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_598_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2243LU));
}

/* SessionSecurityDiagnostics - ns=0;i=12860 */

static UA_StatusCode function_namespace0_generated_599_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2243LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_599_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU));
}

/* ClientCertificate - ns=0;i=12869 */

static UA_StatusCode function_namespace0_generated_600_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12869LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientCertificate"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_600_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12869LU));
}

/* SecurityPolicyUri - ns=0;i=12868 */

static UA_StatusCode function_namespace0_generated_601_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12868LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityPolicyUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_601_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12868LU));
}

/* SecurityMode - ns=0;i=12867 */

static UA_StatusCode function_namespace0_generated_602_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12867LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityMode"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_602_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12867LU));
}

/* TransportProtocol - ns=0;i=12866 */

static UA_StatusCode function_namespace0_generated_603_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12866LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportProtocol"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_603_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12866LU));
}

/* Encoding - ns=0;i=12865 */

static UA_StatusCode function_namespace0_generated_604_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12865LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Encoding"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_604_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12865LU));
}

/* AuthenticationMechanism - ns=0;i=12864 */

static UA_StatusCode function_namespace0_generated_605_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12864LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuthenticationMechanism"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_605_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12864LU));
}

/* ClientUserIdHistory - ns=0;i=12863 */

static UA_StatusCode function_namespace0_generated_606_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12863LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdHistory"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_606_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12863LU));
}

/* ClientUserIdOfSession - ns=0;i=12862 */

static UA_StatusCode function_namespace0_generated_607_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12862LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdOfSession"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_607_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12862LU));
}

/* SessionId - ns=0;i=12861 */

static UA_StatusCode function_namespace0_generated_608_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12861LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_608_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12861LU));
}

/* SessionsDiagnosticsSummaryType - ns=0;i=2026 */

static UA_StatusCode function_namespace0_generated_609_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionsDiagnosticsSummaryType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2026LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionsDiagnosticsSummaryType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_609_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2026LU));
}

/* SessionSecurityDiagnosticsArray - ns=0;i=2028 */

static UA_StatusCode function_namespace0_generated_610_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2028LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2026LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2243LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_610_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2028LU));
}

/* SessionDiagnosticsArray - ns=0;i=2027 */

static UA_StatusCode function_namespace0_generated_611_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2027LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2026LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2196LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_611_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2027LU));
}

/* <ClientName> - ns=0;i=12097 */

static UA_StatusCode function_namespace0_generated_612_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<ClientName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12097LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2026LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "<ClientName>"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2029LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_612_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12097LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=12152 */

static UA_StatusCode function_namespace0_generated_613_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12152LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12097LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_613_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12152LU));
}

/* SessionSecurityDiagnostics - ns=0;i=12142 */

static UA_StatusCode function_namespace0_generated_614_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12097LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2244LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_614_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU));
}

/* ClientCertificate - ns=0;i=12151 */

static UA_StatusCode function_namespace0_generated_615_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12151LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientCertificate"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_615_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12151LU));
}

/* SecurityPolicyUri - ns=0;i=12150 */

static UA_StatusCode function_namespace0_generated_616_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12150LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityPolicyUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_616_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12150LU));
}

/* SecurityMode - ns=0;i=12149 */

static UA_StatusCode function_namespace0_generated_617_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12149LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityMode"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_617_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12149LU));
}

/* TransportProtocol - ns=0;i=12148 */

static UA_StatusCode function_namespace0_generated_618_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12148LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransportProtocol"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_618_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12148LU));
}

/* Encoding - ns=0;i=12147 */

static UA_StatusCode function_namespace0_generated_619_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12147LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Encoding"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_619_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12147LU));
}

/* AuthenticationMechanism - ns=0;i=12146 */

static UA_StatusCode function_namespace0_generated_620_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12146LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AuthenticationMechanism"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_620_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12146LU));
}

/* ClientUserIdHistory - ns=0;i=12145 */

static UA_StatusCode function_namespace0_generated_621_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12145LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdHistory"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_621_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12145LU));
}

/* ClientUserIdOfSession - ns=0;i=12144 */

static UA_StatusCode function_namespace0_generated_622_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12144LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientUserIdOfSession"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_622_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12144LU));
}

/* SessionId - ns=0;i=12143 */

static UA_StatusCode function_namespace0_generated_623_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12143LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_623_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12143LU));
}

/* SessionDiagnostics - ns=0;i=12098 */

static UA_StatusCode function_namespace0_generated_624_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12097LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2197LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_624_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU));
}

/* UnregisterNodesCount - ns=0;i=12141 */

static UA_StatusCode function_namespace0_generated_625_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12141LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnregisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_625_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12141LU));
}

/* RegisterNodesCount - ns=0;i=12140 */

static UA_StatusCode function_namespace0_generated_626_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12140LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RegisterNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_626_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12140LU));
}

/* QueryNextCount - ns=0;i=12139 */

static UA_StatusCode function_namespace0_generated_627_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12139LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_627_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12139LU));
}

/* QueryFirstCount - ns=0;i=12138 */

static UA_StatusCode function_namespace0_generated_628_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12138LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "QueryFirstCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_628_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12138LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=12137 */

static UA_StatusCode function_namespace0_generated_629_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12137LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_629_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12137LU));
}

/* BrowseNextCount - ns=0;i=12136 */

static UA_StatusCode function_namespace0_generated_630_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12136LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseNextCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_630_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12136LU));
}

/* BrowseCount - ns=0;i=12135 */

static UA_StatusCode function_namespace0_generated_631_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12135LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BrowseCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_631_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12135LU));
}

/* DeleteReferencesCount - ns=0;i=12134 */

static UA_StatusCode function_namespace0_generated_632_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12134LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_632_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12134LU));
}

/* DeleteNodesCount - ns=0;i=12133 */

static UA_StatusCode function_namespace0_generated_633_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12133LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_633_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12133LU));
}

/* AddReferencesCount - ns=0;i=12132 */

static UA_StatusCode function_namespace0_generated_634_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12132LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddReferencesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_634_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12132LU));
}

/* AddNodesCount - ns=0;i=12131 */

static UA_StatusCode function_namespace0_generated_635_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12131LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddNodesCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_635_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12131LU));
}

/* DeleteSubscriptionsCount - ns=0;i=12130 */

static UA_StatusCode function_namespace0_generated_636_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12130LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_636_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12130LU));
}

/* TransferSubscriptionsCount - ns=0;i=12129 */

static UA_StatusCode function_namespace0_generated_637_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12129LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_637_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12129LU));
}

/* RepublishCount - ns=0;i=12128 */

static UA_StatusCode function_namespace0_generated_638_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12128LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RepublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_638_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12128LU));
}

/* PublishCount - ns=0;i=12127 */

static UA_StatusCode function_namespace0_generated_639_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12127LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_639_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12127LU));
}

/* SetPublishingModeCount - ns=0;i=12126 */

static UA_StatusCode function_namespace0_generated_640_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12126LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetPublishingModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_640_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12126LU));
}

/* ModifySubscriptionCount - ns=0;i=12125 */

static UA_StatusCode function_namespace0_generated_641_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12125LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifySubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_641_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12125LU));
}

/* CreateSubscriptionCount - ns=0;i=12124 */

static UA_StatusCode function_namespace0_generated_642_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12124LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_642_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12124LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=12123 */

static UA_StatusCode function_namespace0_generated_643_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12123LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_643_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12123LU));
}

/* SetTriggeringCount - ns=0;i=12122 */

static UA_StatusCode function_namespace0_generated_644_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12122LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetTriggeringCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_644_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12122LU));
}

/* SetMonitoringModeCount - ns=0;i=12121 */

static UA_StatusCode function_namespace0_generated_645_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12121LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SetMonitoringModeCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_645_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12121LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=12120 */

static UA_StatusCode function_namespace0_generated_646_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12120LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_646_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12120LU));
}

/* CreateMonitoredItemsCount - ns=0;i=12119 */

static UA_StatusCode function_namespace0_generated_647_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12119LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_647_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12119LU));
}

/* CallCount - ns=0;i=12118 */

static UA_StatusCode function_namespace0_generated_648_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12118LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CallCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_648_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12118LU));
}

/* HistoryUpdateCount - ns=0;i=12117 */

static UA_StatusCode function_namespace0_generated_649_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12117LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryUpdateCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_649_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12117LU));
}

/* WriteCount - ns=0;i=12116 */

static UA_StatusCode function_namespace0_generated_650_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12116LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "WriteCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_650_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12116LU));
}

/* HistoryReadCount - ns=0;i=12115 */

static UA_StatusCode function_namespace0_generated_651_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12115LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_651_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12115LU));
}

/* ReadCount - ns=0;i=12114 */

static UA_StatusCode function_namespace0_generated_652_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12114LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReadCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_652_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12114LU));
}

/* UnauthorizedRequestCount - ns=0;i=12113 */

static UA_StatusCode function_namespace0_generated_653_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12113LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_653_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12113LU));
}

/* TotalRequestCount - ns=0;i=12112 */

static UA_StatusCode function_namespace0_generated_654_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12112LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "TotalRequestCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_654_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12112LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=12111 */

static UA_StatusCode function_namespace0_generated_655_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12111LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_655_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12111LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=12110 */

static UA_StatusCode function_namespace0_generated_656_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12110LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_656_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12110LU));
}

/* CurrentSubscriptionsCount - ns=0;i=12109 */

static UA_StatusCode function_namespace0_generated_657_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12109LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_657_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12109LU));
}

/* ClientLastContactTime - ns=0;i=12108 */

static UA_StatusCode function_namespace0_generated_658_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12108LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientLastContactTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_658_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12108LU));
}

/* ClientConnectionTime - ns=0;i=12107 */

static UA_StatusCode function_namespace0_generated_659_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12107LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientConnectionTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_659_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12107LU));
}

/* MaxResponseMessageSize - ns=0;i=12106 */

static UA_StatusCode function_namespace0_generated_660_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12106LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxResponseMessageSize"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_660_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12106LU));
}

/* ActualSessionTimeout - ns=0;i=12105 */

static UA_StatusCode function_namespace0_generated_661_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12105LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ActualSessionTimeout"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_661_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12105LU));
}

/* LocaleIds - ns=0;i=12104 */

static UA_StatusCode function_namespace0_generated_662_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12104LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocaleIds"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_662_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12104LU));
}

/* EndpointUrl - ns=0;i=12103 */

static UA_StatusCode function_namespace0_generated_663_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12103LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EndpointUrl"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_663_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12103LU));
}

/* ServerUri - ns=0;i=12102 */

static UA_StatusCode function_namespace0_generated_664_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12102LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_664_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12102LU));
}

/* ClientDescription - ns=0;i=12101 */

static UA_StatusCode function_namespace0_generated_665_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12101LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ClientDescription"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_665_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12101LU));
}

/* SessionName - ns=0;i=12100 */

static UA_StatusCode function_namespace0_generated_666_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12100LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_666_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12100LU));
}

/* SessionId - ns=0;i=12099 */

static UA_StatusCode function_namespace0_generated_667_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12099LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_667_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12099LU));
}

/* InterfaceTypes - ns=0;i=17708 */

static UA_StatusCode function_namespace0_generated_668_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "InterfaceTypes");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17708LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 86LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 35LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InterfaceTypes"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_668_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17708LU));
}

/* BaseInterfaceType - ns=0;i=17602 */

static UA_StatusCode function_namespace0_generated_669_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "BaseInterfaceType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17602LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BaseInterfaceType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17602LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 35LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17708LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_669_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17602LU));
}

/* BuildInfoType - ns=0;i=3051 */

static UA_StatusCode function_namespace0_generated_670_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 338LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfoType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3051LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BuildInfoType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_670_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3051LU));
}

/* ServerStatusType - ns=0;i=2138 */

static UA_StatusCode function_namespace0_generated_671_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 862LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2138LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerStatusType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_671_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2138LU));
}

/* OperationLimitsType - ns=0;i=11564 */

static UA_StatusCode function_namespace0_generated_672_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimitsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 61LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OperationLimitsType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_672_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU));
}

/* MaxMonitoredItemsPerCall - ns=0;i=11574 */

static UA_StatusCode function_namespace0_generated_673_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11574LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxMonitoredItemsPerCall"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_673_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11574LU));
}

/* MaxNodesPerNodeManagement - ns=0;i=11573 */

static UA_StatusCode function_namespace0_generated_674_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11573LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerNodeManagement"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_674_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11573LU));
}

/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11572 */

static UA_StatusCode function_namespace0_generated_675_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11572LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerTranslateBrowsePathsToNodeIds"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_675_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11572LU));
}

/* MaxNodesPerRegisterNodes - ns=0;i=11571 */

static UA_StatusCode function_namespace0_generated_676_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11571LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerRegisterNodes"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_676_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11571LU));
}

/* MaxNodesPerBrowse - ns=0;i=11570 */

static UA_StatusCode function_namespace0_generated_677_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11570LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerBrowse"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_677_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11570LU));
}

/* MaxNodesPerMethodCall - ns=0;i=11569 */

static UA_StatusCode function_namespace0_generated_678_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11569LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerMethodCall"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_678_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11569LU));
}

/* MaxNodesPerWrite - ns=0;i=11567 */

static UA_StatusCode function_namespace0_generated_679_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11567LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerWrite"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_679_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11567LU));
}

/* MaxNodesPerRead - ns=0;i=11565 */

static UA_StatusCode function_namespace0_generated_680_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11565LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerRead"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_680_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11565LU));
}

/* ServerRedundancyType - ns=0;i=2034 */

static UA_StatusCode function_namespace0_generated_681_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancyType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2034LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerRedundancyType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_681_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2034LU));
}

/* RedundancySupport - ns=0;i=2035 */

static UA_StatusCode function_namespace0_generated_682_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 851LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2035LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2034LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RedundancySupport"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_682_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2035LU));
}

/* VendorServerInfoType - ns=0;i=2033 */

static UA_StatusCode function_namespace0_generated_683_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfoType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2033LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "VendorServerInfoType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_683_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2033LU));
}

/* ServerDiagnosticsType - ns=0;i=2020 */

static UA_StatusCode function_namespace0_generated_684_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerDiagnosticsType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_684_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU));
}

/* SessionsDiagnosticsSummary - ns=0;i=2744 */

static UA_StatusCode function_namespace0_generated_685_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionsDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2744LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionsDiagnosticsSummary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2026LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_685_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2744LU));
}

/* SessionSecurityDiagnosticsArray - ns=0;i=3130 */

static UA_StatusCode function_namespace0_generated_686_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3130LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2744LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2243LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_686_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3130LU));
}

/* SessionDiagnosticsArray - ns=0;i=3129 */

static UA_StatusCode function_namespace0_generated_687_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3129LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2744LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2196LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_687_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3129LU));
}

/* EnabledFlag - ns=0;i=2025 */

static UA_StatusCode function_namespace0_generated_688_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 3;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnabledFlag");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2025LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnabledFlag"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_688_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2025LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=2023 */

static UA_StatusCode function_namespace0_generated_689_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2023LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_689_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2023LU));
}

/* SamplingIntervalDiagnosticsArray - ns=0;i=2022 */

static UA_StatusCode function_namespace0_generated_690_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2022LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SamplingIntervalDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2164LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_690_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2022LU));
}

/* ServerDiagnosticsSummary - ns=0;i=2021 */

static UA_StatusCode function_namespace0_generated_691_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 859LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerDiagnosticsSummary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_691_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU));
}

/* RejectedRequestsCount - ns=0;i=3128 */

static UA_StatusCode function_namespace0_generated_692_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3128LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RejectedRequestsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_692_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3128LU));
}

/* SecurityRejectedRequestsCount - ns=0;i=3127 */

static UA_StatusCode function_namespace0_generated_693_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3127LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityRejectedRequestsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_693_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3127LU));
}

/* CumulatedSubscriptionCount - ns=0;i=3126 */

static UA_StatusCode function_namespace0_generated_694_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3126LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CumulatedSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_694_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3126LU));
}

/* CurrentSubscriptionCount - ns=0;i=3125 */

static UA_StatusCode function_namespace0_generated_695_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3125LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_695_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3125LU));
}

/* PublishingIntervalCount - ns=0;i=3124 */

static UA_StatusCode function_namespace0_generated_696_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3124LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingIntervalCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_696_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3124LU));
}

/* SessionAbortCount - ns=0;i=3122 */

static UA_StatusCode function_namespace0_generated_697_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3122LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionAbortCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_697_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3122LU));
}

/* SessionTimeoutCount - ns=0;i=3121 */

static UA_StatusCode function_namespace0_generated_698_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3121LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionTimeoutCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_698_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3121LU));
}

/* RejectedSessionCount - ns=0;i=3120 */

static UA_StatusCode function_namespace0_generated_699_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3120LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RejectedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_699_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3120LU));
}

/* SecurityRejectedSessionCount - ns=0;i=3119 */

static UA_StatusCode function_namespace0_generated_700_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3119LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityRejectedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_700_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3119LU));
}

/* CumulatedSessionCount - ns=0;i=3118 */

static UA_StatusCode function_namespace0_generated_701_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3118LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CumulatedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_701_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3118LU));
}

/* CurrentSessionCount - ns=0;i=3117 */

static UA_StatusCode function_namespace0_generated_702_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3117LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_702_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3117LU));
}

/* ServerViewCount - ns=0;i=3116 */

static UA_StatusCode function_namespace0_generated_703_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3116LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerViewCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_703_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3116LU));
}

/* ServerCapabilitiesType - ns=0;i=2013 */

static UA_StatusCode function_namespace0_generated_704_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilitiesType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2013LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerCapabilitiesType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_704_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2013LU));
}

/* MaxMonitoredItemsQueueSize - ns=0;i=31770 */

static UA_StatusCode function_namespace0_generated_705_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsQueueSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 31770LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2013LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxMonitoredItemsQueueSize"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_705_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 31770LU));
}

/* OperationLimits - ns=0;i=11551 */

static UA_StatusCode function_namespace0_generated_706_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11551LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2013LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OperationLimits"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_706_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11551LU));
}

/* ServerType - ns=0;i=2004 */

static UA_StatusCode function_namespace0_generated_707_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2004LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_707_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2004LU));
}

/* Server - ns=0;i=2253 */

static UA_StatusCode function_namespace0_generated_708_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.eventNotifier = UA_EVENTNOTIFIER_SUBSCRIBE_TO_EVENT;
attr.displayName = UA_LOCALIZEDTEXT("", "Server");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 85LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 35LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Server"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2004LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_708_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU));
}

/* Auditing - ns=0;i=2994 */

static UA_StatusCode function_namespace0_generated_709_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Auditing");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2994LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Auditing"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_709_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2994LU));
}

/* ServerRedundancy - ns=0;i=2296 */

static UA_StatusCode function_namespace0_generated_710_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancy");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2296LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerRedundancy"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2034LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_710_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2296LU));
}

/* RedundancySupport - ns=0;i=3709 */

static UA_StatusCode function_namespace0_generated_711_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 851LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3709LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2296LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RedundancySupport"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_711_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3709LU));
}

/* VendorServerInfo - ns=0;i=2295 */

static UA_StatusCode function_namespace0_generated_712_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2295LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "VendorServerInfo"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2033LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_712_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2295LU));
}

/* ServerDiagnostics - ns=0;i=2274 */

static UA_StatusCode function_namespace0_generated_713_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2274LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerDiagnostics"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2020LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_713_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2274LU));
}

/* SessionsDiagnosticsSummary - ns=0;i=3706 */

static UA_StatusCode function_namespace0_generated_714_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionsDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3706LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2274LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionsDiagnosticsSummary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2026LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_714_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3706LU));
}

/* SessionSecurityDiagnosticsArray - ns=0;i=3708 */

static UA_StatusCode function_namespace0_generated_715_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3708LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3706LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionSecurityDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2243LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_715_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3708LU));
}

/* SessionDiagnosticsArray - ns=0;i=3707 */

static UA_StatusCode function_namespace0_generated_716_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3707LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3706LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2196LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_716_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3707LU));
}

/* EnabledFlag - ns=0;i=2294 */

static UA_StatusCode function_namespace0_generated_717_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 3;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnabledFlag");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2294LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2274LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnabledFlag"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_717_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2294LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=2290 */

static UA_StatusCode function_namespace0_generated_718_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2290LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2274LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_718_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2290LU));
}

/* ServerDiagnosticsSummary - ns=0;i=2275 */

static UA_StatusCode function_namespace0_generated_719_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 859LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2274LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerDiagnosticsSummary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2150LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_719_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU));
}

/* RejectedSessionCount - ns=0;i=3705 */

static UA_StatusCode function_namespace0_generated_720_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3705LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RejectedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_720_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3705LU));
}

/* RejectedRequestsCount - ns=0;i=2288 */

static UA_StatusCode function_namespace0_generated_721_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2288LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RejectedRequestsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_721_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2288LU));
}

/* SecurityRejectedRequestsCount - ns=0;i=2287 */

static UA_StatusCode function_namespace0_generated_722_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2287LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityRejectedRequestsCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_722_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2287LU));
}

/* CumulatedSubscriptionCount - ns=0;i=2286 */

static UA_StatusCode function_namespace0_generated_723_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2286LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CumulatedSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_723_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2286LU));
}

/* CurrentSubscriptionCount - ns=0;i=2285 */

static UA_StatusCode function_namespace0_generated_724_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2285LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSubscriptionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_724_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2285LU));
}

/* PublishingIntervalCount - ns=0;i=2284 */

static UA_StatusCode function_namespace0_generated_725_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2284LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishingIntervalCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_725_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2284LU));
}

/* SessionAbortCount - ns=0;i=2282 */

static UA_StatusCode function_namespace0_generated_726_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2282LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionAbortCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_726_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2282LU));
}

/* SessionTimeoutCount - ns=0;i=2281 */

static UA_StatusCode function_namespace0_generated_727_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2281LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SessionTimeoutCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_727_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2281LU));
}

/* SecurityRejectedSessionCount - ns=0;i=2279 */

static UA_StatusCode function_namespace0_generated_728_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2279LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecurityRejectedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_728_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2279LU));
}

/* CumulatedSessionCount - ns=0;i=2278 */

static UA_StatusCode function_namespace0_generated_729_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2278LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CumulatedSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_729_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2278LU));
}

/* CurrentSessionCount - ns=0;i=2277 */

static UA_StatusCode function_namespace0_generated_730_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2277LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentSessionCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_730_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2277LU));
}

/* ServerViewCount - ns=0;i=2276 */

static UA_StatusCode function_namespace0_generated_731_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2276LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerViewCount"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_731_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2276LU));
}

/* ServerCapabilities - ns=0;i=2268 */

static UA_StatusCode function_namespace0_generated_732_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilities");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerCapabilities"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2013LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_732_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU));
}

/* SoftwareCertificates - ns=0;i=3704 */

static UA_StatusCode function_namespace0_generated_733_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 344LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareCertificates");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SoftwareCertificates"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_733_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3704LU));
}

/* MaxMonitoredItemsQueueSize - ns=0;i=31916 */

static UA_StatusCode function_namespace0_generated_734_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsQueueSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 31916LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxMonitoredItemsQueueSize"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_734_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 31916LU));
}

/* AggregateFunctions - ns=0;i=2997 */

static UA_StatusCode function_namespace0_generated_735_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2997LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AggregateFunctions"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_735_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2997LU));
}

/* ModellingRules - ns=0;i=2996 */

static UA_StatusCode function_namespace0_generated_736_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRules");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2996LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModellingRules"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_736_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2996LU));
}

/* MaxHistoryContinuationPoints - ns=0;i=2737 */

static UA_StatusCode function_namespace0_generated_737_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxHistoryContinuationPoints");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2737LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxHistoryContinuationPoints"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_737_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2737LU));
}

/* MaxQueryContinuationPoints - ns=0;i=2736 */

static UA_StatusCode function_namespace0_generated_738_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxQueryContinuationPoints");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2736LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxQueryContinuationPoints"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_738_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2736LU));
}

/* MaxBrowseContinuationPoints - ns=0;i=2735 */

static UA_StatusCode function_namespace0_generated_739_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxBrowseContinuationPoints");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2735LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxBrowseContinuationPoints"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_739_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2735LU));
}

/* MinSupportedSampleRate - ns=0;i=2272 */

static UA_StatusCode function_namespace0_generated_740_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MinSupportedSampleRate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2272LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MinSupportedSampleRate"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_740_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2272LU));
}

/* LocaleIdArray - ns=0;i=2271 */

static UA_StatusCode function_namespace0_generated_741_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIdArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2271LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "LocaleIdArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_741_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2271LU));
}

/* ServerProfileArray - ns=0;i=2269 */

static UA_StatusCode function_namespace0_generated_742_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerProfileArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2269LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerProfileArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_742_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2269LU));
}

/* OperationLimits - ns=0;i=11704 */

static UA_StatusCode function_namespace0_generated_743_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OperationLimits"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11564LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_743_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU));
}

/* MaxMonitoredItemsPerCall - ns=0;i=11714 */

static UA_StatusCode function_namespace0_generated_744_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11714LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxMonitoredItemsPerCall"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_744_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11714LU));
}

/* MaxNodesPerNodeManagement - ns=0;i=11713 */

static UA_StatusCode function_namespace0_generated_745_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11713LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerNodeManagement"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_745_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11713LU));
}

/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11712 */

static UA_StatusCode function_namespace0_generated_746_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11712LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerTranslateBrowsePathsToNodeIds"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_746_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11712LU));
}

/* MaxNodesPerRegisterNodes - ns=0;i=11711 */

static UA_StatusCode function_namespace0_generated_747_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11711LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerRegisterNodes"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_747_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11711LU));
}

/* MaxNodesPerBrowse - ns=0;i=11710 */

static UA_StatusCode function_namespace0_generated_748_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11710LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerBrowse"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_748_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11710LU));
}

/* MaxNodesPerMethodCall - ns=0;i=11709 */

static UA_StatusCode function_namespace0_generated_749_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11709LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerMethodCall"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_749_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11709LU));
}

/* MaxNodesPerWrite - ns=0;i=11707 */

static UA_StatusCode function_namespace0_generated_750_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11707LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerWrite"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_750_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11707LU));
}

/* MaxNodesPerRead - ns=0;i=11705 */

static UA_StatusCode function_namespace0_generated_751_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11705LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11704LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxNodesPerRead"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_751_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11705LU));
}

/* HistoryServerCapabilities - ns=0;i=11192 */

static UA_StatusCode function_namespace0_generated_752_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryServerCapabilities");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2268LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "HistoryServerCapabilities"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2330LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_752_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU));
}

/* DeleteEventCapability - ns=0;i=11502 */

static UA_StatusCode function_namespace0_generated_753_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11502LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteEventCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_753_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11502LU));
}

/* UpdateEventCapability - ns=0;i=11283 */

static UA_StatusCode function_namespace0_generated_754_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UpdateEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11283LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UpdateEventCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_754_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11283LU));
}

/* ReplaceEventCapability - ns=0;i=11282 */

static UA_StatusCode function_namespace0_generated_755_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11282LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReplaceEventCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_755_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11282LU));
}

/* InsertEventCapability - ns=0;i=11281 */

static UA_StatusCode function_namespace0_generated_756_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InsertEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11281LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InsertEventCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_756_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11281LU));
}

/* InsertAnnotationCapability - ns=0;i=11275 */

static UA_StatusCode function_namespace0_generated_757_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InsertAnnotationCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11275LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InsertAnnotationCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_757_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11275LU));
}

/* MaxReturnEventValues - ns=0;i=11274 */

static UA_StatusCode function_namespace0_generated_758_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnEventValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11274LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxReturnEventValues"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_758_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11274LU));
}

/* MaxReturnDataValues - ns=0;i=11273 */

static UA_StatusCode function_namespace0_generated_759_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnDataValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11273LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MaxReturnDataValues"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_759_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11273LU));
}

/* AccessHistoryEventsCapability - ns=0;i=11242 */

static UA_StatusCode function_namespace0_generated_760_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryEventsCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11242LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AccessHistoryEventsCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_760_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11242LU));
}

/* AggregateFunctions - ns=0;i=11201 */

static UA_StatusCode function_namespace0_generated_761_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11201LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AggregateFunctions"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_761_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11201LU));
}

/* DeleteAtTimeCapability - ns=0;i=11200 */

static UA_StatusCode function_namespace0_generated_762_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteAtTimeCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11200LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteAtTimeCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_762_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11200LU));
}

/* DeleteRawCapability - ns=0;i=11199 */

static UA_StatusCode function_namespace0_generated_763_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteRawCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11199LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DeleteRawCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_763_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11199LU));
}

/* UpdateDataCapability - ns=0;i=11198 */

static UA_StatusCode function_namespace0_generated_764_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UpdateDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11198LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "UpdateDataCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_764_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11198LU));
}

/* ReplaceDataCapability - ns=0;i=11197 */

static UA_StatusCode function_namespace0_generated_765_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11197LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReplaceDataCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_765_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11197LU));
}

/* InsertDataCapability - ns=0;i=11196 */

static UA_StatusCode function_namespace0_generated_766_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InsertDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11196LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InsertDataCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_766_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11196LU));
}

/* AccessHistoryDataCapability - ns=0;i=11193 */

static UA_StatusCode function_namespace0_generated_767_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11193LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11192LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AccessHistoryDataCapability"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_767_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11193LU));
}

/* ServiceLevel - ns=0;i=2267 */

static UA_StatusCode function_namespace0_generated_768_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServiceLevel");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2267LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServiceLevel"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_768_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2267LU));
}

/* ServerStatus - ns=0;i=2256 */

static UA_StatusCode function_namespace0_generated_769_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 862LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatus");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerStatus"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2138LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_769_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU));
}

/* ShutdownReason - ns=0;i=2993 */

static UA_StatusCode function_namespace0_generated_770_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ShutdownReason");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2993LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ShutdownReason"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_770_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2993LU));
}

/* SecondsTillShutdown - ns=0;i=2992 */

static UA_StatusCode function_namespace0_generated_771_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecondsTillShutdown");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2992LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SecondsTillShutdown"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_771_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2992LU));
}

/* BuildInfo - ns=0;i=2260 */

static UA_StatusCode function_namespace0_generated_772_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 338LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BuildInfo"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3051LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_772_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU));
}

/* BuildDate - ns=0;i=2266 */

static UA_StatusCode function_namespace0_generated_773_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildDate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2266LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BuildDate"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_773_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2266LU));
}

/* BuildNumber - ns=0;i=2265 */

static UA_StatusCode function_namespace0_generated_774_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildNumber");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2265LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "BuildNumber"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_774_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2265LU));
}

/* SoftwareVersion - ns=0;i=2264 */

static UA_StatusCode function_namespace0_generated_775_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareVersion");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2264LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SoftwareVersion"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_775_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2264LU));
}

/* ManufacturerName - ns=0;i=2263 */

static UA_StatusCode function_namespace0_generated_776_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ManufacturerName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2263LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ManufacturerName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_776_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2263LU));
}

/* ProductUri - ns=0;i=2262 */

static UA_StatusCode function_namespace0_generated_777_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ProductUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2262LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ProductUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_777_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2262LU));
}

/* ProductName - ns=0;i=2261 */

static UA_StatusCode function_namespace0_generated_778_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ProductName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2261LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2260LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ProductName"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_778_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2261LU));
}

/* State - ns=0;i=2259 */

static UA_StatusCode function_namespace0_generated_779_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 852LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2259LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "State"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_779_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2259LU));
}

/* CurrentTime - ns=0;i=2258 */

static UA_StatusCode function_namespace0_generated_780_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2258LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "CurrentTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_780_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2258LU));
}

/* StartTime - ns=0;i=2257 */

static UA_StatusCode function_namespace0_generated_781_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "StartTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2257LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2256LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "StartTime"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_781_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2257LU));
}

/* NamespaceArray - ns=0;i=2255 */

static UA_StatusCode function_namespace0_generated_782_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2255LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamespaceArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_782_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2255LU));
}

/* ServerArray - ns=0;i=2254 */

static UA_StatusCode function_namespace0_generated_783_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2254LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ServerArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_783_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2254LU));
}

/* PublishSubscribe - ns=0;i=14443 */

static UA_StatusCode function_namespace0_generated_784_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishSubscribe");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishSubscribe"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14416LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_784_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU));
}

/* DefaultDatagramPublisherId - ns=0;i=25480 */

static UA_StatusCode function_namespace0_generated_785_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DefaultDatagramPublisherId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25480LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DefaultDatagramPublisherId"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_785_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25480LU));
}

/* PubSubConfiguration - ns=0;i=25451 */

static UA_StatusCode function_namespace0_generated_786_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PubSubConfiguration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25451LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PubSubConfiguration"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_786_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25451LU));
}

/* ReserveIds - ns=0;i=25474 */

static UA_StatusCode function_namespace0_generated_787_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "ReserveIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25474LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25451LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ReserveIds"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_787_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25474LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=25476 */

static UA_StatusCode function_namespace0_generated_788_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 3;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DefaultPublisherId</Name>"
              "<DataType>"
                "<Identifier>i=24</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>WriterGroupIds</Name>"
              "<DataType>"
                "<Identifier>i=5</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>DataSetWriterIds</Name>"
              "<DataType>"
                "<Identifier>i=5</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=25476: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25476LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25474LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_788_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25476LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=25475 */

static UA_StatusCode function_namespace0_generated_789_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 3;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>TransportProfileUri</Name>"
              "<DataType>"
                "<Identifier>i=12</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>NumReqWriterGroupIds</Name>"
              "<DataType>"
                "<Identifier>i=5</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>NumReqDataSetWriterIds</Name>"
              "<DataType>"
                "<Identifier>i=5</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=25475: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25475LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25474LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_789_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25475LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* SubscribedDataSets - ns=0;i=23658 */

static UA_StatusCode function_namespace0_generated_790_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscribedDataSets");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23658LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SubscribedDataSets"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23795LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_790_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23658LU));
}

/* SupportedTransportProfiles - ns=0;i=17481 */

static UA_StatusCode function_namespace0_generated_791_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SupportedTransportProfiles");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17481LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "SupportedTransportProfiles"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_791_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17481LU));
}

/* PublishedDataSets - ns=0;i=17371 */

static UA_StatusCode function_namespace0_generated_792_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "PublishedDataSets");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17371LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "PublishedDataSets"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14477LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_792_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17371LU));
}

/* RemoveConnection - ns=0;i=17369 */

static UA_StatusCode function_namespace0_generated_793_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "RemoveConnection");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17369LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "RemoveConnection"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_793_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17369LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=17370 */

static UA_StatusCode function_namespace0_generated_794_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConnectionId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17370: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17370LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17369LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_794_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17370LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* AddConnection - ns=0;i=17366 */

static UA_StatusCode function_namespace0_generated_795_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "AddConnection");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17366LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14443LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "AddConnection"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_795_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17366LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=17368 */

static UA_StatusCode function_namespace0_generated_796_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ConnectionId</Name>"
              "<DataType>"
                "<Identifier>i=17</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17368: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17368LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17366LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_796_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17368LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=17367 */

static UA_StatusCode function_namespace0_generated_797_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>Configuration</Name>"
              "<DataType>"
                "<Identifier>i=15617</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
              "<Description xmlns:p5=\"http://www.w3.org/2001/XMLSchema-instance\" p5:nil=\"true\"/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=17367: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17367LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17366LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_797_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17367LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* ResendData - ns=0;i=12873 */

static UA_StatusCode function_namespace0_generated_798_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "ResendData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12873LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ResendData"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_798_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12873LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=12874 */

static UA_StatusCode function_namespace0_generated_799_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscriptionId</Name>"
              "<DataType>"
                "<Identifier>i=7</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=12874: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12874LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12873LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_799_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12874LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* GetMonitoredItems - ns=0;i=11492 */

static UA_StatusCode function_namespace0_generated_800_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "GetMonitoredItems");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11492LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2253LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "GetMonitoredItems"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_800_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11492LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=11494 */

static UA_StatusCode function_namespace0_generated_801_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ServerHandles</Name>"
              "<DataType>"
                "<Identifier>i=7</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions>"
                "<UInt32>0</UInt32>"
              "</ArrayDimensions>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>ClientHandles</Name>"
              "<DataType>"
                "<Identifier>i=7</Identifier>"
              "</DataType>"
              "<ValueRank>1</ValueRank>"
              "<ArrayDimensions>"
                "<UInt32>0</UInt32>"
              "</ArrayDimensions>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=11494: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11494LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11492LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OutputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_801_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11494LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=11493 */

static UA_StatusCode function_namespace0_generated_802_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<ListOfExtensionObject xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">"
        "<ExtensionObject>"
          "<TypeId>"
            "<Identifier>i=297</Identifier>"
          "</TypeId>"
          "<Body>"
            "<Argument>"
              "<Name>SubscriptionId</Name>"
              "<DataType>"
                "<Identifier>i=7</Identifier>"
              "</DataType>"
              "<ValueRank>-1</ValueRank>"
              "<ArrayDimensions/>"
            "</Argument>"
          "</Body>"
        "</ExtensionObject>"
      "</ListOfExtensionObject>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
if(UA_Variant_isScalar(&attr.value) && attr.value.data != NULL) {
    UA_LOG_WARNING(UA_Server_getConfig(server)->logging,
                  UA_LOGCATEGORY_USERLAND,
                  "Node ns=0;i=11493: ValueRank=1 but the XML value is scalar. Auto-wrapping into a one-element array.");
    attr.value.arrayLength = 1;
}
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11493LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11492LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "InputArguments"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_802_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11493LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* VendorServerInfo - ns=0;i=2011 */

static UA_StatusCode function_namespace0_generated_803_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2011LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2004LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "VendorServerInfo"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2033LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_803_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2011LU));
}

/* ModellingRuleType - ns=0;i=77 */

static UA_StatusCode function_namespace0_generated_804_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRuleType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ModellingRuleType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_804_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU));
}

/* ExposesItsArray - ns=0;i=83 */

static UA_StatusCode function_namespace0_generated_805_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ExposesItsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 83LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "ExposesItsArray"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 83LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12860LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 83LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12816LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 83LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12779LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 83LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12784LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_805_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 83LU));
}

/* NamingRule - ns=0;i=114 */

static UA_StatusCode function_namespace0_generated_806_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<Int32 xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">3</Int32>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 114LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 83LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamingRule"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_806_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 114LU));
}

/* Optional - ns=0;i=80 */

static UA_StatusCode function_namespace0_generated_807_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Optional");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Optional"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11551LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11565LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11567LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11569LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11570LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11571LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11572LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11573LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11574LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 31770LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2022LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3190LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2757LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2758LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2759LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9000LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9001LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11110LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11111LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9015LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9016LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9017LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 25432LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14493LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14499LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16994LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16997LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23622LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16759LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14555LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14558LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17203LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17427LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17465LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14225LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15927LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17969LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17992LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21094LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15303LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23797LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23800LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23802LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23805LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23811LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23814LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23816LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23819LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14645LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14646LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17633LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16312LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16598LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14432LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15115LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15118LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2366LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2367LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2370LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2371LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_807_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU));
}

/* NamingRule - ns=0;i=113 */

static UA_StatusCode function_namespace0_generated_808_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<Int32 xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">2</Int32>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 113LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamingRule"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_808_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 113LU));
}

/* Mandatory - ns=0;i=78 */

static UA_StatusCode function_namespace0_generated_809_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Mandatory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Mandatory"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12169LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2011LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2035LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7611LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2021LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3116LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3117LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3118LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3119LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3120LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3121LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3122LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3124LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3125LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3126LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3127LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3128LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2023LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12142LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12152LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12143LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12144LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12145LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12146LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12147LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12148LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12149LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12150LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12151LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2027LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2028LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12098LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12099LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12100LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12101LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12102LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12103LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12104LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12105LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12106LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12107LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12108LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12109LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12110LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12111LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12112LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12113LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12114LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12115LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12116LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12117LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12118LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12119LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12120LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12121LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12122LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12123LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12124LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12125LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12126LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12127LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12128LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12129LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12130LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12131LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12132LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12133LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12134LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12135LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12136LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12137LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12138LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12139LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12140LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12141LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12861LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12862LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12863LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12864LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12865LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12866LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12867LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12868LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12869LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2744LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3129LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3130LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2025LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12817LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12818LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12819LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12820LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12821LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12822LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12823LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12824LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12825LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12826LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12827LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12828LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12829LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12830LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12831LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12832LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12833LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12834LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12835LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12836LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12837LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12838LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12839LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12840LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12841LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12842LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12843LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12844LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12845LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12846LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12847LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12848LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12849LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12850LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12851LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12852LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12853LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12854LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12855LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12856LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12857LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12858LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12859LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12780LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12781LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12782LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12783LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2166LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11697LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11698LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11699LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2151LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2152LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2153LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2154LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2155LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2156LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2157LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2159LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2160LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2161LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2162LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2163LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7595LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7597LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2030LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3131LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3132LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3133LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3134LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3135LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3136LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3137LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3138LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3139LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3140LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3141LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3142LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3143LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8898LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11891LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3151LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3152LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3153LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3154LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3155LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3156LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3157LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3158LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3159LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3160LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3161LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3162LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3163LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3164LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3165LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3166LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3167LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3168LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3169LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3170LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3171LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3172LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3173LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3174LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3175LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3176LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3177LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3178LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2031LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3179LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3180LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3181LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3182LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3183LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3184LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3185LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3186LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3187LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2245LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2246LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2247LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2248LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2249LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2250LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2251LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2252LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3058LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2032LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12785LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12786LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12787LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12788LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12789LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12790LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12791LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12792LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12793LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12794LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12795LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12796LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12797LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12798LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12799LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12800LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12801LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12802LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12803LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12804LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12805LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12806LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12807LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12808LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12809LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12810LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12811LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12812LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12813LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12814LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12815LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2173LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2174LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2175LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2176LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2177LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8888LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2179LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2180LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2181LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2182LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2183LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2184LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2185LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2186LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2187LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2188LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2189LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2190LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2191LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2998LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2193LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8889LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8890LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8891LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8892LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8893LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8894LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8895LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8896LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8897LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8902LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2198LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2199LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2200LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2201LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2202LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2203LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2204LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3050LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2205LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2206LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2207LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2208LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2209LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8900LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11892LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2217LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2218LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2219LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2220LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2221LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2222LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2223LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2224LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2225LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2226LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2227LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2228LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2229LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2230LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2231LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2232LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2233LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2234LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2235LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2236LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2237LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2238LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2239LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2240LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2241LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2242LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2730LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2731LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2042LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2043LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2044LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2045LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2046LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2047LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2050LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2051LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2134LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17222LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11851LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2053LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2054LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2055LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2056LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2057LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2128LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2129LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9003LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2756LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8996LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11112LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11113LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9009LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9010LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3874LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9011LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9012LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9020LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9021LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9022LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9023LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9024LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9025LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9026LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9028LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9027LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9029LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 9030LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3876LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12913LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17479LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14494LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14495LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14500LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16995LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16996LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17007LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14434LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15844LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15845LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14519LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15229LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14648LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15584LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14548LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14556LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14557LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14559LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14560LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17485LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14221LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17202LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21146LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21149LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14600LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14601LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17428LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17456LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17507LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17508LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14226LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17724LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15265LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15266LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17976LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17987LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17993LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17736LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17737LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17738LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17739LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17740LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17306LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17710LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15299LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15300LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21092LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21093LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17493LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15307LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15308LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23798LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23799LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23801LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23803LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23804LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23806LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23808LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23809LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23810LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23812LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23813LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23815LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23817LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23818LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23820LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23829LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23830LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23831LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17744LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17745LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17490LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17749LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17750LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14644LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17632LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14595LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14418LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17478LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14423LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15533LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16599LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 16600LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14433LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17292LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17706LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21083LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21084LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21086LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21097LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21098LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21099LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21100LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21101LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21102LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17494LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15311LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 21103LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15316LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15114LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15116LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15117LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15119LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15120LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2369LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2374LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2375LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 2377LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11241LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11461LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12078LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_809_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU));
}

/* NamingRule - ns=0;i=112 */

static UA_StatusCode function_namespace0_generated_810_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<Int32 xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">1</Int32>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 112LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamingRule"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_810_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 112LU));
}

/* MandatoryPlaceholder - ns=0;i=11510 */

static UA_StatusCode function_namespace0_generated_811_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "MandatoryPlaceholder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11510LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "MandatoryPlaceholder"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_811_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11510LU));
}

/* NamingRule - ns=0;i=11511 */

static UA_StatusCode function_namespace0_generated_812_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<Int32 xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">1</Int32>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11511LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11510LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamingRule"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_812_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11511LU));
}

/* OptionalPlaceholder - ns=0;i=11508 */

static UA_StatusCode function_namespace0_generated_813_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OptionalPlaceholder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OptionalPlaceholder"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12097LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14478LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17310LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23796LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 23807LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17743LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 14417LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 17325LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 18076LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_813_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU));
}

/* NamingRule - ns=0;i=11509 */

static UA_StatusCode function_namespace0_generated_814_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<Int32 xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">2</Int32>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11509LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11508LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamingRule"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_814_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 11509LU));
}

/* NamingRule - ns=0;i=111 */

static UA_StatusCode function_namespace0_generated_815_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 120LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<Int32 xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">1</Int32>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 111LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 77LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamingRule"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 111LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 78LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_815_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 111LU));
}

/* DataTypeEncodingType - ns=0;i=76 */

static UA_StatusCode function_namespace0_generated_816_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeEncodingType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 76LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataTypeEncodingType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_816_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 76LU));
}

/* Default Binary - ns=0;i=8251 */

static UA_StatusCode function_namespace0_generated_817_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8251LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Default Binary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8251LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 38LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7594LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_817_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8251LU));
}

/* Default Binary - ns=0;i=298 */

static UA_StatusCode function_namespace0_generated_818_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 298LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Default Binary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 298LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 38LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 296LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_818_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 298LU));
}

/* Default JSON - ns=0;i=15376 */

static UA_StatusCode function_namespace0_generated_819_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default JSON");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15376LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Default JSON"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15376LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 38LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 887LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_819_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15376LU));
}

/* Default JSON - ns=0;i=15375 */

static UA_StatusCode function_namespace0_generated_820_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default JSON");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15375LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Default JSON"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15375LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 38LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 884LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_820_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15375LU));
}

/* DataTypeSystemType - ns=0;i=75 */

static UA_StatusCode function_namespace0_generated_821_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeSystemType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 75LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataTypeSystemType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_821_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 75LU));
}

/* OPC Binary - ns=0;i=93 */

static UA_StatusCode function_namespace0_generated_822_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OPC Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 93LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 90LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 35LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "OPC Binary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 75LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_822_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 93LU));
}

/* XML Schema - ns=0;i=92 */

static UA_StatusCode function_namespace0_generated_823_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "XML Schema");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 92LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 90LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 35LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "XML Schema"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 75LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_823_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 92LU));
}

/* DataTypeDictionaryType - ns=0;i=72 */

static UA_StatusCode function_namespace0_generated_824_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDictionaryType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 72LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataTypeDictionaryType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_824_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 72LU));
}

/* Opc.Ua - ns=0;i=7617 */

static UA_StatusCode function_namespace0_generated_825_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_BYTESTRING_NULL;
retVal |= UA_ByteString_allocBuffer(&xmlValue, 236386);
if(retVal == UA_STATUSCODE_GOOD) {
    char *buf_0 = "<Value>"
    "<ByteString xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">PG9wYzpUeXBlRGljdGlvbmFyeQ0KICB4bWxuczpvcGM9Imh0dHA6Ly9vcGNmb3VuZGF0aW9uLm9y"
"Zy9CaW5hcnlTY2hlbWEvIg0KICB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1M"
"U2NoZW1hLWluc3RhbmNlIg0KICB4bWxuczp1YT0iaHR0cDovL29wY2ZvdW5kYXRpb24ub3JnL1VB"
"LyINCiAgeG1sbnM6dG5zPSJodHRwOi8vb3BjZm91bmRhdGlvbi5vcmcvVUEvIg0KICBEZWZhdWx0"
"Qnl0ZU9yZGVyPSJMaXR0bGVFbmRpYW4iDQogIFRhcmdldE5hbWVzcGFjZT0iaHR0cDovL29wY2Zv"
"dW5kYXRpb24ub3JnL1VBLyINCj4NCg0KICA8b3BjOkltcG9ydCBOYW1lc3BhY2U9Imh0dHA6Ly9v"
"cGNmb3VuZGF0aW9uLm9yZy9CaW5hcnlTY2hlbWEvIiAvPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iWG1sRWxlbWVudCI+DQogICAgPG9wYzpEb2N1bWVudGF0aW9uPkFuIFhNTCBlbGVt"
"ZW50IGVuY29kZWQgYXMgYSBVVEYtOCBzdHJpbmcuPC9vcGM6RG9jdW1lbnRhdGlvbj4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9Ikxlbmd0aCIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlZhbHVlIiBUeXBlTmFtZT0ib3BjOkNoYXIiIExlbmd0aEZpZWxkPSJMZW5n"
"dGgiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUg"
"TmFtZT0iTm9kZUlkVHlwZSIgTGVuZ3RoSW5CaXRzPSI2Ij4NCiAgICA8b3BjOkRvY3VtZW50YXRp"
"b24+VGhlIHBvc3NpYmxlIGVuY29kaW5ncyBmb3IgYSBOb2RlSWQgdmFsdWUuPC9vcGM6RG9jdW1l"
"bnRhdGlvbj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJUd29CeXRlIiBWYWx1ZT0i"
"MCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJGb3VyQnl0ZSIgVmFsdWU9IjEi"
"IC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTnVtZXJpYyIgVmFsdWU9IjIiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU3RyaW5nIiBWYWx1ZT0iMyIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJHdWlkIiBWYWx1ZT0iNCIgLz4NCiAgICA8b3Bj"
"OkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJCeXRlU3RyaW5nIiBWYWx1ZT0iNSIgLz4NCiAgPC9vcGM6"
"RW51bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJUd29CeXRlTm9k"
"ZUlkIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IklkZW50aWZpZXIiIFR5cGVOYW1lPSJvcGM6Qnl0"
"ZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBO"
"YW1lPSJGb3VyQnl0ZU5vZGVJZCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1lc3BhY2VJbmRl"
"eCIgVHlwZU5hbWU9Im9wYzpCeXRlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSWRlbnRpZmll"
"ciIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQog"
"IDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iTnVtZXJpY05vZGVJZCI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOYW1lc3BhY2VJbmRleCIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJJZGVudGlmaWVyIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgPC9v"
"cGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTdHJpbmdO"
"b2RlSWQiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmFtZXNwYWNlSW5kZXgiIFR5cGVOYW1lPSJv"
"cGM6VUludDE2IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSWRlbnRpZmllciIgVHlwZU5hbWU9"
"Im9wYzpDaGFyQXJyYXkiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iR3VpZE5vZGVJZCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1l"
"c3BhY2VJbmRleCIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJJZGVudGlmaWVyIiBUeXBlTmFtZT0ib3BjOkd1aWQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRU"
"eXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQnl0ZVN0cmluZ05vZGVJZCI+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1lc3BhY2VJbmRleCIgVHlwZU5hbWU9Im9wYzpVSW50MTYi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJZGVudGlmaWVyIiBUeXBlTmFtZT0ib3BjOkJ5dGVT"
"dHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iTm9kZUlkIj4NCiAgICA8b3BjOkRvY3VtZW50YXRpb24+QW4gaWRlbnRpZmllciBm"
"b3IgYSBub2RlIGluIGEgVUEgc2VydmVyIGFkZHJlc3Mgc3BhY2UuPC9vcGM6RG9jdW1lbnRhdGlv"
"bj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVJZFR5cGUiIFR5cGVOYW1lPSJ1YTpOb2RlSWRU"
"eXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzZXJ2ZWQxIiBUeXBlTmFtZT0ib3BjOkJp"
"dCIgTGVuZ3RoPSIyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVHdvQnl0ZSIgVHlwZU5hbWU9"
"InVhOlR3b0J5dGVOb2RlSWQiIFN3aXRjaEZpZWxkPSJOb2RlSWRUeXBlIiBTd2l0Y2hWYWx1ZT0i"
"MCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkZvdXJCeXRlIiBUeXBlTmFtZT0idWE6Rm91ckJ5"
"dGVOb2RlSWQiIFN3aXRjaEZpZWxkPSJOb2RlSWRUeXBlIiBTd2l0Y2hWYWx1ZT0iMSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik51bWVyaWMiIFR5cGVOYW1lPSJ1YTpOdW1lcmljTm9kZUlkIiBT"
"d2l0Y2hGaWVsZD0iTm9kZUlkVHlwZSIgU3dpdGNoVmFsdWU9IjIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJTdHJpbmciIFR5cGVOYW1lPSJ1YTpTdHJpbmdOb2RlSWQiIFN3aXRjaEZpZWxkPSJO"
"b2RlSWRUeXBlIiBTd2l0Y2hWYWx1ZT0iMyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ikd1aWQi"
"IFR5cGVOYW1lPSJ1YTpHdWlkTm9kZUlkIiBTd2l0Y2hGaWVsZD0iTm9kZUlkVHlwZSIgU3dpdGNo"
"VmFsdWU9IjQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJCeXRlU3RyaW5nIiBUeXBlTmFtZT0i"
"dWE6Qnl0ZVN0cmluZ05vZGVJZCIgU3dpdGNoRmllbGQ9Ik5vZGVJZFR5cGUiIFN3aXRjaFZhbHVl"
"PSI1IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9IkV4cGFuZGVkTm9kZUlkIj4NCiAgICA8b3BjOkRvY3VtZW50YXRpb24+QW4gaWRlbnRp"
"ZmllciBmb3IgYSBub2RlIGluIGEgVUEgc2VydmVyIGFkZHJlc3Mgc3BhY2UgcXVhbGlmaWVkIHdp"
"dGggYSBjb21wbGV0ZSBuYW1lc3BhY2Ugc3RyaW5nLjwvb3BjOkRvY3VtZW50YXRpb24+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJOb2RlSWRUeXBlIiBUeXBlTmFtZT0idWE6Tm9kZUlkVHlwZSIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlckluZGV4U3BlY2lmaWVkIiBUeXBlTmFtZT0ib3Bj"
"OkJpdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWVzcGFjZVVSSVNwZWNpZmllZCIgVHlw"
"ZU5hbWU9Im9wYzpCaXQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUd29CeXRlIiBUeXBlTmFt";
    memcpy(xmlValue.data + 0, buf_0, 4861);
    char *buf_1 = "ZT0idWE6VHdvQnl0ZU5vZGVJZCIgU3dpdGNoRmllbGQ9Ik5vZGVJZFR5cGUiIFN3aXRjaFZhbHVl"
"PSIwIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRm91ckJ5dGUiIFR5cGVOYW1lPSJ1YTpGb3Vy"
"Qnl0ZU5vZGVJZCIgU3dpdGNoRmllbGQ9Ik5vZGVJZFR5cGUiIFN3aXRjaFZhbHVlPSIxIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iTnVtZXJpYyIgVHlwZU5hbWU9InVhOk51bWVyaWNOb2RlSWQi"
"IFN3aXRjaEZpZWxkPSJOb2RlSWRUeXBlIiBTd2l0Y2hWYWx1ZT0iMiIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlN0cmluZyIgVHlwZU5hbWU9InVhOlN0cmluZ05vZGVJZCIgU3dpdGNoRmllbGQ9"
"Ik5vZGVJZFR5cGUiIFN3aXRjaFZhbHVlPSIzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iR3Vp"
"ZCIgVHlwZU5hbWU9InVhOkd1aWROb2RlSWQiIFN3aXRjaEZpZWxkPSJOb2RlSWRUeXBlIiBTd2l0"
"Y2hWYWx1ZT0iNCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJ5dGVTdHJpbmciIFR5cGVOYW1l"
"PSJ1YTpCeXRlU3RyaW5nTm9kZUlkIiBTd2l0Y2hGaWVsZD0iTm9kZUlkVHlwZSIgU3dpdGNoVmFs"
"dWU9IjUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1lc3BhY2VVUkkiIFR5cGVOYW1lPSJv"
"cGM6Q2hhckFycmF5IiBTd2l0Y2hGaWVsZD0iTmFtZXNwYWNlVVJJU3BlY2lmaWVkIi8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJTZXJ2ZXJJbmRleCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFN3aXRj"
"aEZpZWxkPSJTZXJ2ZXJJbmRleFNwZWNpZmllZCIvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4N"
"Cg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFtZT0iU3RhdHVzQ29kZSIgTGVuZ3RoSW5CaXRzPSIzMiIg"
"Qnl0ZU9yZGVyU2lnbmlmaWNhbnQ9InRydWUiPg0KICAgIDxvcGM6RG9jdW1lbnRhdGlvbj5BIDMy"
"LWJpdCBzdGF0dXMgY29kZSB2YWx1ZS48L29wYzpEb2N1bWVudGF0aW9uPg0KICA8L29wYzpPcGFx"
"dWVUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRGlhZ25vc3RpY0luZm8iPg0K"
"ICAgIDxvcGM6RG9jdW1lbnRhdGlvbj5BIHJlY3Vyc2l2ZSBzdHJ1Y3R1cmUgY29udGFpbmluZyBk"
"aWFnbm9zdGljIGluZm9ybWF0aW9uIGFzc29jaWF0ZWQgd2l0aCBhIHN0YXR1cyBjb2RlLjwvb3Bj"
"OkRvY3VtZW50YXRpb24+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTeW1ib2xpY0lkU3BlY2lmaWVk"
"IiBUeXBlTmFtZT0ib3BjOkJpdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWVzcGFjZVVS"
"SVNwZWNpZmllZCIgVHlwZU5hbWU9Im9wYzpCaXQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJM"
"b2NhbGl6ZWRUZXh0U3BlY2lmaWVkIiBUeXBlTmFtZT0ib3BjOkJpdCIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IkxvY2FsZVNwZWNpZmllZCIgVHlwZU5hbWU9Im9wYzpCaXQiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJBZGRpdGlvbmFsSW5mb1NwZWNpZmllZCIgVHlwZU5hbWU9Im9wYzpCaXQi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJbm5lclN0YXR1c0NvZGVTcGVjaWZpZWQiIFR5cGVO"
"YW1lPSJvcGM6Qml0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSW5uZXJEaWFnbm9zdGljSW5m"
"b1NwZWNpZmllZCIgVHlwZU5hbWU9Im9wYzpCaXQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJS"
"ZXNlcnZlZDEiIFR5cGVOYW1lPSJvcGM6Qml0IiBMZW5ndGg9IjEiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJTeW1ib2xpY0lkIiBUeXBlTmFtZT0ib3BjOkludDMyIiBTd2l0Y2hGaWVsZD0iU3lt"
"Ym9saWNJZFNwZWNpZmllZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWVzcGFjZVVSSSIg"
"VHlwZU5hbWU9Im9wYzpJbnQzMiIgU3dpdGNoRmllbGQ9Ik5hbWVzcGFjZVVSSVNwZWNpZmllZCIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkxvY2FsZSIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgU3dp"
"dGNoRmllbGQ9IkxvY2FsZVNwZWNpZmllZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkxvY2Fs"
"aXplZFRleHQiIFR5cGVOYW1lPSJvcGM6SW50MzIiIFN3aXRjaEZpZWxkPSJMb2NhbGl6ZWRUZXh0"
"U3BlY2lmaWVkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWRkaXRpb25hbEluZm8iIFR5cGVO"
"YW1lPSJvcGM6Q2hhckFycmF5IiBTd2l0Y2hGaWVsZD0iQWRkaXRpb25hbEluZm9TcGVjaWZpZWQi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJbm5lclN0YXR1c0NvZGUiIFR5cGVOYW1lPSJ1YTpT"
"dGF0dXNDb2RlIiBTd2l0Y2hGaWVsZD0iSW5uZXJTdGF0dXNDb2RlU3BlY2lmaWVkIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iSW5uZXJEaWFnbm9zdGljSW5mbyIgVHlwZU5hbWU9InVhOkRpYWdu"
"b3N0aWNJbmZvIiBTd2l0Y2hGaWVsZD0iSW5uZXJEaWFnbm9zdGljSW5mb1NwZWNpZmllZCIgLz4N"
"CiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJR"
"dWFsaWZpZWROYW1lIj4NCiAgICA8b3BjOkRvY3VtZW50YXRpb24+QSBzdHJpbmcgcXVhbGlmaWVk"
"IHdpdGggYSBuYW1lc3BhY2UgaW5kZXguPC9vcGM6RG9jdW1lbnRhdGlvbj4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ik5hbWVzcGFjZUluZGV4IiBUeXBlTmFtZT0ib3BjOlVJbnQxNiIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9Ik5hbWUiIFR5cGVOYW1lPSJvcGM6Q2hhckFycmF5IiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkxvY2FsaXpl"
"ZFRleHQiPg0KICAgIDxvcGM6RG9jdW1lbnRhdGlvbj5BIHN0cmluZyBxdWFsaWZpZWQgd2l0aCBh"
"IG5hbWVzcGFjZSBpbmRleC48L29wYzpEb2N1bWVudGF0aW9uPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iTG9jYWxlU3BlY2lmaWVkIiBUeXBlTmFtZT0ib3BjOkJpdCIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlRleHRTcGVjaWZpZWQiIFR5cGVOYW1lPSJvcGM6Qml0IiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVzZXJ2ZWQxIiBUeXBlTmFtZT0ib3BjOkJpdCIgTGVuZ3RoPSI2IiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iTG9jYWxlIiBUeXBlTmFtZT0ib3BjOkNoYXJBcnJheSIgU3dpdGNo"
"RmllbGQ9IkxvY2FsZVNwZWNpZmllZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRleHQiIFR5"
"cGVOYW1lPSJvcGM6Q2hhckFycmF5IiBTd2l0Y2hGaWVsZD0iVGV4dFNwZWNpZmllZCIgLz4NCiAg"
"PC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJEYXRh"
"VmFsdWUiPg0KICAgIDxvcGM6RG9jdW1lbnRhdGlvbj5BIHZhbHVlIHdpdGggYW4gYXNzb2NpYXRl"
"ZCB0aW1lc3RhbXAsIGFuZCBxdWFsaXR5Ljwvb3BjOkRvY3VtZW50YXRpb24+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJWYWx1ZVNwZWNpZmllZCIgVHlwZU5hbWU9Im9wYzpCaXQiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJTdGF0dXNDb2RlU3BlY2lmaWVkIiBUeXBlTmFtZT0ib3BjOkJpdCIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlNvdXJjZVRpbWVzdGFtcFNwZWNpZmllZCIgVHlwZU5hbWU9"
"Im9wYzpCaXQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2ZXJUaW1lc3RhbXBTcGVjaWZp"
"ZWQiIFR5cGVOYW1lPSJvcGM6Qml0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU291cmNlUGlj";
    memcpy(xmlValue.data + 4861, buf_1, 4864);
    char *buf_2 = "b3NlY29uZHNTcGVjaWZpZWQiIFR5cGVOYW1lPSJvcGM6Qml0IiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iU2VydmVyUGljb3NlY29uZHNTcGVjaWZpZWQiIFR5cGVOYW1lPSJvcGM6Qml0IiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzZXJ2ZWQxIiBUeXBlTmFtZT0ib3BjOkJpdCIgTGVuZ3Ro"
"PSIyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVmFsdWUiIFR5cGVOYW1lPSJ1YTpWYXJpYW50"
"IiBTd2l0Y2hGaWVsZD0iVmFsdWVTcGVjaWZpZWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJT"
"dGF0dXNDb2RlIiBUeXBlTmFtZT0idWE6U3RhdHVzQ29kZSIgU3dpdGNoRmllbGQ9IlN0YXR1c0Nv"
"ZGVTcGVjaWZpZWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTb3VyY2VUaW1lc3RhbXAiIFR5"
"cGVOYW1lPSJvcGM6RGF0ZVRpbWUiIFN3aXRjaEZpZWxkPSJTb3VyY2VUaW1lc3RhbXBTcGVjaWZp"
"ZWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTb3VyY2VQaWNvc2Vjb25kcyIgVHlwZU5hbWU9"
"Im9wYzpVSW50MTYiIFN3aXRjaEZpZWxkPSJTb3VyY2VQaWNvc2Vjb25kc1NwZWNpZmllZCIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlclRpbWVzdGFtcCIgVHlwZU5hbWU9Im9wYzpEYXRl"
"VGltZSIgU3dpdGNoRmllbGQ9IlNlcnZlclRpbWVzdGFtcFNwZWNpZmllZCIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlNlcnZlclBpY29zZWNvbmRzIiBUeXBlTmFtZT0ib3BjOlVJbnQxNiIgU3dp"
"dGNoRmllbGQ9IlNlcnZlclBpY29zZWNvbmRzU3BlY2lmaWVkIiAvPg0KICA8L29wYzpTdHJ1Y3R1"
"cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkV4dGVuc2lvbk9iamVjdCI+"
"DQogICAgPG9wYzpEb2N1bWVudGF0aW9uPkEgc2VyaWFsaXplZCBvYmplY3QgcHJlZml4ZWQgd2l0"
"aCBpdHMgZGF0YSB0eXBlIGlkZW50aWZpZXIuPC9vcGM6RG9jdW1lbnRhdGlvbj4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlR5cGVJZFNwZWNpZmllZCIgVHlwZU5hbWU9Im9wYzpCaXQiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJCaW5hcnlCb2R5IiBUeXBlTmFtZT0ib3BjOkJpdCIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IlhtbEJvZHkiIFR5cGVOYW1lPSJvcGM6Qml0IiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iUmVzZXJ2ZWQxIiBUeXBlTmFtZT0ib3BjOkJpdCIgTGVuZ3RoPSI1IiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iVHlwZUlkIiBUeXBlTmFtZT0idWE6RXhwYW5kZWROb2RlSWQi"
"IFN3aXRjaEZpZWxkPSJUeXBlSWRTcGVjaWZpZWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJC"
"b2R5TGVuZ3RoIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Qm9keSIgVHlwZU5hbWU9Im9wYzpCeXRlIiBMZW5ndGhGaWVsZD0iQm9keUxlbmd0aCIgLz4NCiAg"
"PC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJWYXJp"
"YW50Ij4NCiAgICA8b3BjOkRvY3VtZW50YXRpb24+QSB1bmlvbiBvZiBzZXZlcmFsIHR5cGVzLjwv"
"b3BjOkRvY3VtZW50YXRpb24+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJWYXJpYW50VHlwZSIgVHlw"
"ZU5hbWU9Im9wYzpCaXQiIExlbmd0aD0iNiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFycmF5"
"RGltZW5zaW9uc1NwZWNpZmllZCIgVHlwZU5hbWU9Im9wYzpCaXQiIExlbmd0aD0iMSIvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iQXJyYXlMZW5ndGhTcGVjaWZpZWQiIFR5cGVOYW1lPSJvcGM6Qml0"
"IiBMZW5ndGg9IjEiLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFycmF5TGVuZ3RoIiBUeXBlTmFt"
"ZT0ib3BjOkludDMyIiBTd2l0Y2hGaWVsZD0iQXJyYXlMZW5ndGhTcGVjaWZpZWQiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJCb29sZWFuIiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4iIExlbmd0aEZp"
"ZWxkPSJBcnJheUxlbmd0aCIgU3dpdGNoRmllbGQ9IlZhcmlhbnRUeXBlIiBTd2l0Y2hWYWx1ZT0i"
"MSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNCeXRlIiBUeXBlTmFtZT0ib3BjOlNCeXRlIiBM"
"ZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgiIFN3aXRjaEZpZWxkPSJWYXJpYW50VHlwZSIgU3dpdGNo"
"VmFsdWU9IjIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJCeXRlIiBUeXBlTmFtZT0ib3BjOkJ5"
"dGUiIExlbmd0aEZpZWxkPSJBcnJheUxlbmd0aCIgU3dpdGNoRmllbGQ9IlZhcmlhbnRUeXBlIiBT"
"d2l0Y2hWYWx1ZT0iMyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkludDE2IiBUeXBlTmFtZT0i"
"b3BjOkludDE2IiBMZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgiIFN3aXRjaEZpZWxkPSJWYXJpYW50"
"VHlwZSIgU3dpdGNoVmFsdWU9IjQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVSW50MTYiIFR5"
"cGVOYW1lPSJvcGM6VUludDE2IiBMZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgiIFN3aXRjaEZpZWxk"
"PSJWYXJpYW50VHlwZSIgU3dpdGNoVmFsdWU9IjUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJ"
"bnQzMiIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgTGVuZ3RoRmllbGQ9IkFycmF5TGVuZ3RoIiBTd2l0"
"Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRjaFZhbHVlPSI2IiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iVUludDMyIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgTGVuZ3RoRmllbGQ9IkFycmF5TGVu"
"Z3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRjaFZhbHVlPSI3IiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iSW50NjQiIFR5cGVOYW1lPSJvcGM6SW50NjQiIExlbmd0aEZpZWxkPSJB"
"cnJheUxlbmd0aCIgU3dpdGNoRmllbGQ9IlZhcmlhbnRUeXBlIiBTd2l0Y2hWYWx1ZT0iOCIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlVJbnQ2NCIgVHlwZU5hbWU9Im9wYzpVSW50NjQiIExlbmd0"
"aEZpZWxkPSJBcnJheUxlbmd0aCIgU3dpdGNoRmllbGQ9IlZhcmlhbnRUeXBlIiBTd2l0Y2hWYWx1"
"ZT0iOSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkZsb2F0IiBUeXBlTmFtZT0ib3BjOkZsb2F0"
"IiBMZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgiIFN3aXRjaEZpZWxkPSJWYXJpYW50VHlwZSIgU3dp"
"dGNoVmFsdWU9IjEwIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRG91YmxlIiBUeXBlTmFtZT0i"
"b3BjOkRvdWJsZSIgTGVuZ3RoRmllbGQ9IkFycmF5TGVuZ3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFu"
"dFR5cGUiIFN3aXRjaFZhbHVlPSIxMSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN0cmluZyIg"
"VHlwZU5hbWU9Im9wYzpDaGFyQXJyYXkiIExlbmd0aEZpZWxkPSJBcnJheUxlbmd0aCIgU3dpdGNo"
"RmllbGQ9IlZhcmlhbnRUeXBlIiBTd2l0Y2hWYWx1ZT0iMTIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJEYXRlVGltZSIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgTGVuZ3RoRmllbGQ9IkFycmF5"
"TGVuZ3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRjaFZhbHVlPSIxMyIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ikd1aWQiIFR5cGVOYW1lPSJvcGM6R3VpZCIgTGVuZ3RoRmllbGQ9"
"IkFycmF5TGVuZ3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRjaFZhbHVlPSIxNCIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJ5dGVTdHJpbmciIFR5cGVOYW1lPSJvcGM6Qnl0ZVN0";
    memcpy(xmlValue.data + 9725, buf_2, 4864);
    char *buf_3 = "cmluZyIgTGVuZ3RoRmllbGQ9IkFycmF5TGVuZ3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUi"
"IFN3aXRjaFZhbHVlPSIxNSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlhtbEVsZW1lbnQiIFR5"
"cGVOYW1lPSJ1YTpYbWxFbGVtZW50IiBMZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgiIFN3aXRjaEZp"
"ZWxkPSJWYXJpYW50VHlwZSIgU3dpdGNoVmFsdWU9IjE2IiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iTm9kZUlkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiBMZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgi"
"IFN3aXRjaEZpZWxkPSJWYXJpYW50VHlwZSIgU3dpdGNoVmFsdWU9IjE3IiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iRXhwYW5kZWROb2RlSWQiIFR5cGVOYW1lPSJ1YTpFeHBhbmRlZE5vZGVJZCIg"
"TGVuZ3RoRmllbGQ9IkFycmF5TGVuZ3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRj"
"aFZhbHVlPSIxOCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN0YXR1c0NvZGUiIFR5cGVOYW1l"
"PSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgiIFN3aXRjaEZpZWxkPSJW"
"YXJpYW50VHlwZSIgU3dpdGNoVmFsdWU9IjE5IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUXVh"
"bGlmaWVkTmFtZSIgVHlwZU5hbWU9InVhOlF1YWxpZmllZE5hbWUiIExlbmd0aEZpZWxkPSJBcnJh"
"eUxlbmd0aCIgU3dpdGNoRmllbGQ9IlZhcmlhbnRUeXBlIiBTd2l0Y2hWYWx1ZT0iMjAiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJMb2NhbGl6ZWRUZXh0IiBUeXBlTmFtZT0idWE6TG9jYWxpemVk"
"VGV4dCIgTGVuZ3RoRmllbGQ9IkFycmF5TGVuZ3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUi"
"IFN3aXRjaFZhbHVlPSIyMSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkV4dGVuc2lvbk9iamVj"
"dCIgVHlwZU5hbWU9InVhOkV4dGVuc2lvbk9iamVjdCIgTGVuZ3RoRmllbGQ9IkFycmF5TGVuZ3Ro"
"IiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRjaFZhbHVlPSIyMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IkRhdGFWYWx1ZSIgVHlwZU5hbWU9InVhOkRhdGFWYWx1ZSIgTGVuZ3RoRmll"
"bGQ9IkFycmF5TGVuZ3RoIiBTd2l0Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRjaFZhbHVlPSIy"
"MyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlZhcmlhbnQiIFR5cGVOYW1lPSJ1YTpWYXJpYW50"
"IiBMZW5ndGhGaWVsZD0iQXJyYXlMZW5ndGgiIFN3aXRjaEZpZWxkPSJWYXJpYW50VHlwZSIgU3dp"
"dGNoVmFsdWU9IjI0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm8iIFR5"
"cGVOYW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIgTGVuZ3RoRmllbGQ9IkFycmF5TGVuZ3RoIiBTd2l0"
"Y2hGaWVsZD0iVmFyaWFudFR5cGUiIFN3aXRjaFZhbHVlPSIyNSIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9Ik5vT2ZBcnJheURpbWVuc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIFN3aXRjaEZp"
"ZWxkPSJBcnJheURpbWVuc2lvbnNTcGVjaWZpZWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJB"
"cnJheURpbWVuc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIExlbmd0aEZpZWxkPSJOb09mQXJy"
"YXlEaW1lbnNpb25zIiBTd2l0Y2hGaWVsZD0iQXJyYXlEaW1lbnNpb25zU3BlY2lmaWVkIiAvPg0K"
"ICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9Ik5h"
"bWluZ1J1bGVUeXBlIiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1"
"ZSBOYW1lPSJNYW5kYXRvcnkiIFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVl"
"IE5hbWU9Ik9wdGlvbmFsIiBWYWx1ZT0iMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBO"
"YW1lPSJDb25zdHJhaW50IiBWYWx1ZT0iMyIgLz4NCiAgPC9vcGM6RW51bWVyYXRlZFR5cGU+DQog"
"ICAgDQoNCiAgPG9wYzpPcGFxdWVUeXBlIE5hbWU9IkltYWdlQk1QIj4NCiAgPC9vcGM6T3BhcXVl"
"VHlwZT4NCg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFtZT0iSW1hZ2VHSUYiPg0KICA8L29wYzpPcGFx"
"dWVUeXBlPg0KDQogIDxvcGM6T3BhcXVlVHlwZSBOYW1lPSJJbWFnZUpQRyI+DQogIDwvb3BjOk9w"
"YXF1ZVR5cGU+DQoNCiAgPG9wYzpPcGFxdWVUeXBlIE5hbWU9IkltYWdlUE5HIj4NCiAgPC9vcGM6"
"T3BhcXVlVHlwZT4NCg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFtZT0iQXVkaW9EYXRhVHlwZSI+DQog"
"IDwvb3BjOk9wYXF1ZVR5cGU+DQoNCiAgPG9wYzpPcGFxdWVUeXBlIE5hbWU9IkJpdEZpZWxkTWFz"
"a0RhdGFUeXBlIj4NCiAgPC9vcGM6T3BhcXVlVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9IktleVZhbHVlUGFpciIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJLZXkiIFR5cGVOYW1lPSJ1YTpRdWFsaWZpZWROYW1lIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iVmFsdWUiIFR5cGVOYW1lPSJ1YTpWYXJpYW50IiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkFkZGl0aW9u"
"YWxQYXJhbWV0ZXJzVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJOb09mUGFyYW1ldGVycyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IlBhcmFtZXRlcnMiIFR5cGVOYW1lPSJ0bnM6S2V5VmFsdWVQYWly"
"IiBMZW5ndGhGaWVsZD0iTm9PZlBhcmFtZXRlcnMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBl"
"Pg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRXBoZW1lcmFsS2V5VHlwZSIgQmFzZVR5"
"cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQdWJsaWNLZXki"
"IFR5cGVOYW1lPSJvcGM6Qnl0ZVN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNpZ25h"
"dHVyZSIgVHlwZU5hbWU9Im9wYzpCeXRlU3RyaW5nIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlw"
"ZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkVuZHBvaW50VHlwZSIgQmFzZVR5cGU9"
"InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbmRwb2ludFVybCIg"
"VHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eU1v"
"ZGUiIFR5cGVOYW1lPSJ0bnM6TWVzc2FnZVNlY3VyaXR5TW9kZSIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlNlY3VyaXR5UG9saWN5VXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IlRyYW5zcG9ydFByb2ZpbGVVcmkiIFR5cGVOYW1lPSJvcGM6U3RyaW5n"
"IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5h"
"bWU9IlJhdGlvbmFsTnVtYmVyIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9Ik51bWVyYXRvciIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkRlbm9taW5hdG9yIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAg"
"PC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJWZWN0";
    memcpy(xmlValue.data + 14589, buf_3, 4864);
    char *buf_4 = "b3IiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlw"
"ZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlRocmVlRFZlY3RvciIgQmFzZVR5cGU9"
"InRuczpWZWN0b3IiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iWCIgVHlwZU5hbWU9Im9wYzpEb3Vi"
"bGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJZIiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IloiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkNhcnRlc2lh"
"bkNvb3JkaW5hdGVzIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgPC9vcGM6U3Ry"
"dWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJUaHJlZURDYXJ0ZXNp"
"YW5Db29yZGluYXRlcyIgQmFzZVR5cGU9InRuczpDYXJ0ZXNpYW5Db29yZGluYXRlcyI+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJYIiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlkiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iWiIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0K"
"DQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iT3JpZW50YXRpb24iIEJhc2VUeXBlPSJ1YTpF"
"eHRlbnNpb25PYmplY3QiPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVj"
"dHVyZWRUeXBlIE5hbWU9IlRocmVlRE9yaWVudGF0aW9uIiBCYXNlVHlwZT0idG5zOk9yaWVudGF0"
"aW9uIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkEiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iQiIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJDIiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgPC9vcGM6U3RydWN0"
"dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJGcmFtZSIgQmFzZVR5cGU9"
"InVhOkV4dGVuc2lvbk9iamVjdCI+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iVGhyZWVERnJhbWUiIEJhc2VUeXBlPSJ0bnM6RnJhbWUiPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iQ2FydGVzaWFuQ29vcmRpbmF0ZXMiIFR5cGVOYW1lPSJ0bnM6"
"VGhyZWVEQ2FydGVzaWFuQ29vcmRpbmF0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJPcmll"
"bnRhdGlvbiIgVHlwZU5hbWU9InRuczpUaHJlZURPcmllbnRhdGlvbiIgLz4NCiAgPC9vcGM6U3Ry"
"dWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVkVHlwZSBOYW1lPSJPcGVuRmlsZU1vZGUi"
"IExlbmd0aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlJlYWQi"
"IFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IldyaXRlIiBWYWx1"
"ZT0iMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJFcmFzZUV4aXN0aW5nIiBW"
"YWx1ZT0iNCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJBcHBlbmQiIFZhbHVl"
"PSI4IiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBl"
"IE5hbWU9IklkZW50aXR5Q3JpdGVyaWFUeXBlIiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3Bj"
"OkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJVc2VyTmFtZSIgVmFsdWU9IjEiIC8+DQogICAgPG9wYzpF"
"bnVtZXJhdGVkVmFsdWUgTmFtZT0iVGh1bWJwcmludCIgVmFsdWU9IjIiIC8+DQogICAgPG9wYzpF"
"bnVtZXJhdGVkVmFsdWUgTmFtZT0iUm9sZSIgVmFsdWU9IjMiIC8+DQogICAgPG9wYzpFbnVtZXJh"
"dGVkVmFsdWUgTmFtZT0iR3JvdXBJZCIgVmFsdWU9IjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVk"
"VmFsdWUgTmFtZT0iQW5vbnltb3VzIiBWYWx1ZT0iNSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRW"
"YWx1ZSBOYW1lPSJBdXRoZW50aWNhdGVkVXNlciIgVmFsdWU9IjYiIC8+DQogIDwvb3BjOkVudW1l"
"cmF0ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iSWRlbnRpdHlNYXBwaW5n"
"UnVsZVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iQ3JpdGVyaWFUeXBlIiBUeXBlTmFtZT0idG5zOklkZW50aXR5Q3JpdGVyaWFUeXBlIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQ3JpdGVyaWEiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAv"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9"
"IkN1cnJlbmN5VW5pdFR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTnVtZXJpY0NvZGUiIFR5cGVOYW1lPSJvcGM6SW50MTYiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJFeHBvbmVudCIgVHlwZU5hbWU9Im9wYzpTQnl0ZSIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkFscGhhYmV0aWNDb2RlIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkN1cnJlbmN5IiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4"
"dCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVkVHlwZSBO"
"YW1lPSJUcnVzdExpc3RNYXNrcyIgTGVuZ3RoSW5CaXRzPSIzMiI+DQogICAgPG9wYzpFbnVtZXJh"
"dGVkVmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFs"
"dWUgTmFtZT0iVHJ1c3RlZENlcnRpZmljYXRlcyIgVmFsdWU9IjEiIC8+DQogICAgPG9wYzpFbnVt"
"ZXJhdGVkVmFsdWUgTmFtZT0iVHJ1c3RlZENybHMiIFZhbHVlPSIyIiAvPg0KICAgIDxvcGM6RW51"
"bWVyYXRlZFZhbHVlIE5hbWU9Iklzc3VlckNlcnRpZmljYXRlcyIgVmFsdWU9IjQiIC8+DQogICAg"
"PG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSXNzdWVyQ3JscyIgVmFsdWU9IjgiIC8+DQogICAg"
"PG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQWxsIiBWYWx1ZT0iMTUiIC8+DQogIDwvb3BjOkVu"
"dW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVHJ1c3RMaXN0RGF0"
"YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iU3BlY2lmaWVkTGlzdHMiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iTm9PZlRydXN0ZWRDZXJ0aWZpY2F0ZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUcnVzdGVkQ2VydGlmaWNhdGVzIiBUeXBlTmFtZT0ib3Bj"
"OkJ5dGVTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mVHJ1c3RlZENlcnRpZmljYXRlcyIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZUcnVzdGVkQ3JscyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRydXN0ZWRDcmxzIiBUeXBlTmFtZT0ib3BjOkJ5dGVT"
"dHJpbmciIExlbmd0aEZpZWxkPSJOb09mVHJ1c3RlZENybHMiIC8+DQogICAgPG9wYzpGaWVsZCBO";
    memcpy(xmlValue.data + 19453, buf_4, 4864);
    char *buf_5 = "YW1lPSJOb09mSXNzdWVyQ2VydGlmaWNhdGVzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iSXNzdWVyQ2VydGlmaWNhdGVzIiBUeXBlTmFtZT0ib3BjOkJ5dGVT"
"dHJpbmciIExlbmd0aEZpZWxkPSJOb09mSXNzdWVyQ2VydGlmaWNhdGVzIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTm9PZklzc3VlckNybHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJJc3N1ZXJDcmxzIiBUeXBlTmFtZT0ib3BjOkJ5dGVTdHJpbmciIExl"
"bmd0aEZpZWxkPSJOb09mSXNzdWVyQ3JscyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoN"
"CiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJEZWNpbWFsRGF0YVR5cGUiIEJhc2VUeXBlPSJ1"
"YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2NhbGUiIFR5cGVOYW1l"
"PSJvcGM6SW50MTYiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJWYWx1ZSIgVHlwZU5hbWU9Im9w"
"YzpCeXRlU3RyaW5nIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVj"
"dHVyZWRUeXBlIE5hbWU9IkRhdGFUeXBlU2NoZW1hSGVhZGVyIiBCYXNlVHlwZT0idWE6RXh0ZW5z"
"aW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOYW1lc3BhY2VzIiBUeXBlTmFt"
"ZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmFtZXNwYWNlcyIgVHlwZU5h"
"bWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mTmFtZXNwYWNlcyIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5vT2ZTdHJ1Y3R1cmVEYXRhVHlwZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdHJ1Y3R1cmVEYXRhVHlwZXMiIFR5cGVOYW1lPSJ0"
"bnM6U3RydWN0dXJlRGVzY3JpcHRpb24iIExlbmd0aEZpZWxkPSJOb09mU3RydWN0dXJlRGF0YVR5"
"cGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkVudW1EYXRhVHlwZXMiIFR5cGVOYW1l"
"PSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbnVtRGF0YVR5cGVzIiBUeXBl"
"TmFtZT0idG5zOkVudW1EZXNjcmlwdGlvbiIgTGVuZ3RoRmllbGQ9Ik5vT2ZFbnVtRGF0YVR5cGVz"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlNpbXBsZURhdGFUeXBlcyIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNpbXBsZURhdGFUeXBlcyIgVHlw"
"ZU5hbWU9InRuczpTaW1wbGVUeXBlRGVzY3JpcHRpb24iIExlbmd0aEZpZWxkPSJOb09mU2ltcGxl"
"RGF0YVR5cGVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVy"
"ZWRUeXBlIE5hbWU9IkRhdGFUeXBlRGVzY3JpcHRpb24iIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25P"
"YmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVR5cGVJZCIgVHlwZU5hbWU9InVhOk5v"
"ZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWUiIFR5cGVOYW1lPSJ1YTpRdWFsaWZp"
"ZWROYW1lIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRU"
"eXBlIE5hbWU9IlN0cnVjdHVyZURlc2NyaXB0aW9uIiBCYXNlVHlwZT0idG5zOkRhdGFUeXBlRGVz"
"Y3JpcHRpb24iPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVR5cGVJZCIgVHlwZU5hbWU9InVh"
"Ok5vZGVJZCIgU291cmNlVHlwZT0idG5zOkRhdGFUeXBlRGVzY3JpcHRpb24iIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJOYW1lIiBUeXBlTmFtZT0idWE6UXVhbGlmaWVkTmFtZSIgU291cmNlVHlw"
"ZT0idG5zOkRhdGFUeXBlRGVzY3JpcHRpb24iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdHJ1"
"Y3R1cmVEZWZpbml0aW9uIiBUeXBlTmFtZT0idG5zOlN0cnVjdHVyZURlZmluaXRpb24iIC8+DQog"
"IDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRW51"
"bURlc2NyaXB0aW9uIiBCYXNlVHlwZT0idG5zOkRhdGFUeXBlRGVzY3JpcHRpb24iPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iRGF0YVR5cGVJZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgU291cmNlVHlw"
"ZT0idG5zOkRhdGFUeXBlRGVzY3JpcHRpb24iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1l"
"IiBUeXBlTmFtZT0idWE6UXVhbGlmaWVkTmFtZSIgU291cmNlVHlwZT0idG5zOkRhdGFUeXBlRGVz"
"Y3JpcHRpb24iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbnVtRGVmaW5pdGlvbiIgVHlwZU5h"
"bWU9InRuczpFbnVtRGVmaW5pdGlvbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJ1aWx0SW5U"
"eXBlIiBUeXBlTmFtZT0ib3BjOkJ5dGUiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQog"
"IDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iU2ltcGxlVHlwZURlc2NyaXB0aW9uIiBCYXNlVHlw"
"ZT0idG5zOkRhdGFUeXBlRGVzY3JpcHRpb24iPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVR5"
"cGVJZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgU291cmNlVHlwZT0idG5zOkRhdGFUeXBlRGVzY3Jp"
"cHRpb24iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1lIiBUeXBlTmFtZT0idWE6UXVhbGlm"
"aWVkTmFtZSIgU291cmNlVHlwZT0idG5zOkRhdGFUeXBlRGVzY3JpcHRpb24iIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJCYXNlRGF0YVR5cGUiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJCdWlsdEluVHlwZSIgVHlwZU5hbWU9Im9wYzpCeXRlIiAvPg0KICA8"
"L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlVBQmlu"
"YXJ5RmlsZURhdGFUeXBlIiBCYXNlVHlwZT0idG5zOkRhdGFUeXBlU2NoZW1hSGVhZGVyIj4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOYW1lc3BhY2VzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmFtZXNwYWNlcyIgVHlwZU5hbWU9Im9wYzpTdHJpbmci"
"IExlbmd0aEZpZWxkPSJOb09mTmFtZXNwYWNlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5v"
"T2ZTdHJ1Y3R1cmVEYXRhVHlwZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJTdHJ1Y3R1cmVEYXRhVHlwZXMiIFR5cGVOYW1lPSJ0bnM6U3RydWN0dXJlRGVz"
"Y3JpcHRpb24iIExlbmd0aEZpZWxkPSJOb09mU3RydWN0dXJlRGF0YVR5cGVzIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTm9PZkVudW1EYXRhVHlwZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbnVtRGF0YVR5cGVzIiBUeXBlTmFtZT0idG5zOkVudW1E"
"ZXNjcmlwdGlvbiIgTGVuZ3RoRmllbGQ9Ik5vT2ZFbnVtRGF0YVR5cGVzIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTm9PZlNpbXBsZURhdGFUeXBlcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlNpbXBsZURhdGFUeXBlcyIgVHlwZU5hbWU9InRuczpTaW1w"
"bGVUeXBlRGVzY3JpcHRpb24iIExlbmd0aEZpZWxkPSJOb09mU2ltcGxlRGF0YVR5cGVzIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iU2NoZW1hTG9jYXRpb24iIFR5cGVOYW1lPSJvcGM6U3RyaW5n";
    memcpy(xmlValue.data + 24317, buf_5, 4864);
    char *buf_6 = "IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkZpbGVIZWFkZXIiIFR5cGVOYW1lPSJvcGM6"
"SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJGaWxlSGVhZGVyIiBUeXBlTmFtZT0idG5z"
"OktleVZhbHVlUGFpciIgTGVuZ3RoRmllbGQ9Ik5vT2ZGaWxlSGVhZGVyIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iQm9keSIgVHlwZU5hbWU9InVhOlZhcmlhbnQiIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iUHViU3ViU3RhdGUiIExl"
"bmd0aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkRpc2FibGVk"
"IiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJQYXVzZWQiIFZh"
"bHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik9wZXJhdGlvbmFsIiBW"
"YWx1ZT0iMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJFcnJvciIgVmFsdWU9"
"IjMiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUg"
"TmFtZT0iRGF0YVNldE1ldGFEYXRhVHlwZSIgQmFzZVR5cGU9InRuczpEYXRhVHlwZVNjaGVtYUhl"
"YWRlciI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTmFtZXNwYWNlcyIgVHlwZU5hbWU9Im9w"
"YzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWVzcGFjZXMiIFR5cGVOYW1lPSJv"
"cGM6U3RyaW5nIiBMZW5ndGhGaWVsZD0iTm9PZk5hbWVzcGFjZXMiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOb09mU3RydWN0dXJlRGF0YVR5cGVzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iU3RydWN0dXJlRGF0YVR5cGVzIiBUeXBlTmFtZT0idG5zOlN0"
"cnVjdHVyZURlc2NyaXB0aW9uIiBMZW5ndGhGaWVsZD0iTm9PZlN0cnVjdHVyZURhdGFUeXBlcyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZFbnVtRGF0YVR5cGVzIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRW51bURhdGFUeXBlcyIgVHlwZU5hbWU9"
"InRuczpFbnVtRGVzY3JpcHRpb24iIExlbmd0aEZpZWxkPSJOb09mRW51bURhdGFUeXBlcyIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTaW1wbGVEYXRhVHlwZXMiIFR5cGVOYW1lPSJvcGM6"
"SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTaW1wbGVEYXRhVHlwZXMiIFR5cGVOYW1l"
"PSJ0bnM6U2ltcGxlVHlwZURlc2NyaXB0aW9uIiBMZW5ndGhGaWVsZD0iTm9PZlNpbXBsZURhdGFU"
"eXBlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5n"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVzY3JpcHRpb24iIFR5cGVOYW1lPSJ1YTpMb2Nh"
"bGl6ZWRUZXh0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkZpZWxkcyIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkZpZWxkcyIgVHlwZU5hbWU9InRu"
"czpGaWVsZE1ldGFEYXRhIiBMZW5ndGhGaWVsZD0iTm9PZkZpZWxkcyIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IkRhdGFTZXRDbGFzc0lkIiBUeXBlTmFtZT0ib3BjOkd1aWQiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJDb25maWd1cmF0aW9uVmVyc2lvbiIgVHlwZU5hbWU9InRuczpDb25maWd1"
"cmF0aW9uVmVyc2lvbkRhdGFUeXBlIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkZpZWxkTWV0YURhdGEiIEJhc2VUeXBlPSJ1YTpFeHRl"
"bnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmFtZSIgVHlwZU5hbWU9Im9wYzpT"
"dHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5hbWU9InVh"
"OkxvY2FsaXplZFRleHQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJGaWVsZEZsYWdzIiBUeXBl"
"TmFtZT0idG5zOkRhdGFTZXRGaWVsZEZsYWdzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQnVp"
"bHRJblR5cGUiIFR5cGVOYW1lPSJvcGM6Qnl0ZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRh"
"dGFUeXBlIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVmFs"
"dWVSYW5rIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9P"
"ZkFycmF5RGltZW5zaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkFycmF5RGltZW5zaW9ucyIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIExlbmd0aEZpZWxk"
"PSJOb09mQXJyYXlEaW1lbnNpb25zIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWF4U3RyaW5n"
"TGVuZ3RoIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRh"
"dGFTZXRGaWVsZElkIiBUeXBlTmFtZT0ib3BjOkd1aWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJOb09mUHJvcGVydGllcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlByb3BlcnRpZXMiIFR5cGVOYW1lPSJ0bnM6S2V5VmFsdWVQYWlyIiBMZW5ndGhGaWVs"
"ZD0iTm9PZlByb3BlcnRpZXMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"RW51bWVyYXRlZFR5cGUgTmFtZT0iRGF0YVNldEZpZWxkRmxhZ3MiIExlbmd0aEluQml0cz0iMTYi"
"IElzT3B0aW9uU2V0PSJ0cnVlIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOb25l"
"IiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJQcm9tb3RlZEZp"
"ZWxkIiBWYWx1ZT0iMSIgLz4NCiAgPC9vcGM6RW51bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1"
"Y3R1cmVkVHlwZSBOYW1lPSJDb25maWd1cmF0aW9uVmVyc2lvbkRhdGFUeXBlIiBCYXNlVHlwZT0i"
"dWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1ham9yVmVyc2lvbiIg"
"VHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNaW5vclZlcnNp"
"b24iIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0K"
"ICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlB1Ymxpc2hlZERhdGFTZXREYXRhVHlwZSIgQmFz"
"ZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1lIiBU"
"eXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEYXRhU2V0"
"Rm9sZGVyIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0"
"YVNldEZvbGRlciIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mRGF0YVNl"
"dEZvbGRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFTZXRNZXRhRGF0YSIgVHlwZU5h"
"bWU9InRuczpEYXRhU2V0TWV0YURhdGFUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9P"
"ZkV4dGVuc2lvbkZpZWxkcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkV4dGVuc2lvbkZpZWxkcyIgVHlwZU5hbWU9InRuczpLZXlWYWx1ZVBhaXIiIExlbmd0";
    memcpy(xmlValue.data + 29181, buf_6, 4864);
    char *buf_7 = "aEZpZWxkPSJOb09mRXh0ZW5zaW9uRmllbGRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0"
"YVNldFNvdXJjZSIgVHlwZU5hbWU9InVhOkV4dGVuc2lvbk9iamVjdCIgLz4NCiAgPC9vcGM6U3Ry"
"dWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJQdWJsaXNoZWREYXRh"
"U2V0U291cmNlRGF0YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlB1Ymxpc2hl"
"ZFZhcmlhYmxlRGF0YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iUHVibGlzaGVkVmFyaWFibGUiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBdHRyaWJ1dGVJZCIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTYW1wbGluZ0ludGVydmFsSGludCIgVHlwZU5hbWU9"
"Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZWFkYmFuZFR5cGUiIFR5cGVO"
"YW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVhZGJhbmRWYWx1ZSIg"
"VHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJbmRleFJhbmdl"
"IiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN1YnN0aXR1"
"dGVWYWx1ZSIgVHlwZU5hbWU9InVhOlZhcmlhbnQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJO"
"b09mTWV0YURhdGFQcm9wZXJ0aWVzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTWV0YURhdGFQcm9wZXJ0aWVzIiBUeXBlTmFtZT0idWE6UXVhbGlmaWVkTmFt"
"ZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZNZXRhRGF0YVByb3BlcnRpZXMiIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUHVibGlzaGVkRGF0YUl0"
"ZW1zRGF0YVR5cGUiIEJhc2VUeXBlPSJ0bnM6UHVibGlzaGVkRGF0YVNldFNvdXJjZURhdGFUeXBl"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZQdWJsaXNoZWREYXRhIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUHVibGlzaGVkRGF0YSIgVHlwZU5hbWU9"
"InRuczpQdWJsaXNoZWRWYXJpYWJsZURhdGFUeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlB1Ymxpc2hl"
"ZERhdGEiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iUHVibGlzaGVkRXZlbnRzRGF0YVR5cGUiIEJhc2VUeXBlPSJ0bnM6UHVibGlzaGVk"
"RGF0YVNldFNvdXJjZURhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkV2ZW50Tm90aWZp"
"ZXIiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mU2Vs"
"ZWN0ZWRGaWVsZHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJTZWxlY3RlZEZpZWxkcyIgVHlwZU5hbWU9InRuczpTaW1wbGVBdHRyaWJ1dGVPcGVyYW5kIiBM"
"ZW5ndGhGaWVsZD0iTm9PZlNlbGVjdGVkRmllbGRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"RmlsdGVyIiBUeXBlTmFtZT0idG5zOkNvbnRlbnRGaWx0ZXIiIC8+DQogIDwvb3BjOlN0cnVjdHVy"
"ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iRGF0YVNldEZpZWxkQ29udGVu"
"dE1hc2siIExlbmd0aEluQml0cz0iMzIiIElzT3B0aW9uU2V0PSJ0cnVlIj4NCiAgICA8b3BjOkVu"
"dW1lcmF0ZWRWYWx1ZSBOYW1lPSJOb25lIiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1lcmF0"
"ZWRWYWx1ZSBOYW1lPSJTdGF0dXNDb2RlIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0"
"ZWRWYWx1ZSBOYW1lPSJTb3VyY2VUaW1lc3RhbXAiIFZhbHVlPSIyIiAvPg0KICAgIDxvcGM6RW51"
"bWVyYXRlZFZhbHVlIE5hbWU9IlNlcnZlclRpbWVzdGFtcCIgVmFsdWU9IjQiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU291cmNlUGljb1NlY29uZHMiIFZhbHVlPSI4IiAvPg0K"
"ICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNlcnZlclBpY29TZWNvbmRzIiBWYWx1ZT0i"
"MTYiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUmF3RGF0YSIgVmFsdWU9IjMy"
"IiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5h"
"bWU9IkRhdGFTZXRXcml0ZXJEYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOYW1lIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkVuYWJsZWQiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFTZXRXcml0ZXJJZCIgVHlwZU5hbWU9Im9wYzpVSW50MTYi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXRhU2V0RmllbGRDb250ZW50TWFzayIgVHlwZU5h"
"bWU9InRuczpEYXRhU2V0RmllbGRDb250ZW50TWFzayIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IktleUZyYW1lQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iRGF0YVNldE5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iTm9PZkRhdGFTZXRXcml0ZXJQcm9wZXJ0aWVzIiBUeXBlTmFtZT0ib3BjOkludDMy"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVNldFdyaXRlclByb3BlcnRpZXMiIFR5cGVO"
"YW1lPSJ0bnM6S2V5VmFsdWVQYWlyIiBMZW5ndGhGaWVsZD0iTm9PZkRhdGFTZXRXcml0ZXJQcm9w"
"ZXJ0aWVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVHJhbnNwb3J0U2V0dGluZ3MiIFR5cGVO"
"YW1lPSJ1YTpFeHRlbnNpb25PYmplY3QiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNZXNzYWdl"
"U2V0dGluZ3MiIFR5cGVOYW1lPSJ1YTpFeHRlbnNpb25PYmplY3QiIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRGF0YVNldFdyaXRlclRy"
"YW5zcG9ydERhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgPC9vcGM6"
"U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJEYXRhU2V0V3Jp"
"dGVyTWVzc2FnZURhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgPC9v"
"cGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJQdWJTdWJH"
"cm91cERhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ik5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iRW5hYmxlZCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iU2VjdXJpdHlNb2RlIiBUeXBlTmFtZT0idG5zOk1lc3NhZ2VTZWN1cml0eU1vZGUiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eUdyb3VwSWQiIFR5cGVOYW1lPSJvcGM6U3Ry";
    memcpy(xmlValue.data + 34045, buf_7, 4864);
    char *buf_8 = "aW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlNlY3VyaXR5S2V5U2VydmljZXMiIFR5"
"cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eUtleVNl"
"cnZpY2VzIiBUeXBlTmFtZT0idG5zOkVuZHBvaW50RGVzY3JpcHRpb24iIExlbmd0aEZpZWxkPSJO"
"b09mU2VjdXJpdHlLZXlTZXJ2aWNlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1heE5ldHdv"
"cmtNZXNzYWdlU2l6ZSIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJOb09mR3JvdXBQcm9wZXJ0aWVzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iR3JvdXBQcm9wZXJ0aWVzIiBUeXBlTmFtZT0idG5zOktleVZhbHVlUGFp"
"ciIgTGVuZ3RoRmllbGQ9Ik5vT2ZHcm91cFByb3BlcnRpZXMiIC8+DQogIDwvb3BjOlN0cnVjdHVy"
"ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iV3JpdGVyR3JvdXBEYXRhVHlw"
"ZSIgQmFzZVR5cGU9InRuczpQdWJTdWJHcm91cERhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9Ik5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiBTb3VyY2VUeXBlPSJ0bnM6UHViU3ViR3Jv"
"dXBEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuYWJsZWQiIFR5cGVOYW1lPSJv"
"cGM6Qm9vbGVhbiIgU291cmNlVHlwZT0idG5zOlB1YlN1Ykdyb3VwRGF0YVR5cGUiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eU1vZGUiIFR5cGVOYW1lPSJ0bnM6TWVzc2FnZVNlY3Vy"
"aXR5TW9kZSIgU291cmNlVHlwZT0idG5zOlB1YlN1Ykdyb3VwRGF0YVR5cGUiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJTZWN1cml0eUdyb3VwSWQiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiBTb3Vy"
"Y2VUeXBlPSJ0bnM6UHViU3ViR3JvdXBEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5vT2ZTZWN1cml0eUtleVNlcnZpY2VzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iU2VjdXJpdHlLZXlTZXJ2aWNlcyIgVHlwZU5hbWU9InRuczpFbmRwb2lu"
"dERlc2NyaXB0aW9uIiBMZW5ndGhGaWVsZD0iTm9PZlNlY3VyaXR5S2V5U2VydmljZXMiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJNYXhOZXR3b3JrTWVzc2FnZVNpemUiIFR5cGVOYW1lPSJvcGM6"
"VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6UHViU3ViR3JvdXBEYXRhVHlwZSIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5vT2ZHcm91cFByb3BlcnRpZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJHcm91cFByb3BlcnRpZXMiIFR5cGVOYW1lPSJ0bnM6S2V5"
"VmFsdWVQYWlyIiBMZW5ndGhGaWVsZD0iTm9PZkdyb3VwUHJvcGVydGllcyIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IldyaXRlckdyb3VwSWQiIFR5cGVOYW1lPSJvcGM6VUludDE2IiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iUHVibGlzaGluZ0ludGVydmFsIiBUeXBlTmFtZT0ib3BjOkRvdWJs"
"ZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IktlZXBBbGl2ZVRpbWUiIFR5cGVOYW1lPSJvcGM6"
"RG91YmxlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUHJpb3JpdHkiIFR5cGVOYW1lPSJvcGM6"
"Qnl0ZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZMb2NhbGVJZHMiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJMb2NhbGVJZHMiIFR5cGVOYW1lPSJv"
"cGM6U3RyaW5nIiBMZW5ndGhGaWVsZD0iTm9PZkxvY2FsZUlkcyIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkhlYWRlckxheW91dFVyaSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJUcmFuc3BvcnRTZXR0aW5ncyIgVHlwZU5hbWU9InVhOkV4dGVuc2lvbk9i"
"amVjdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1lc3NhZ2VTZXR0aW5ncyIgVHlwZU5hbWU9"
"InVhOkV4dGVuc2lvbk9iamVjdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEYXRhU2V0"
"V3JpdGVycyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRh"
"dGFTZXRXcml0ZXJzIiBUeXBlTmFtZT0idG5zOkRhdGFTZXRXcml0ZXJEYXRhVHlwZSIgTGVuZ3Ro"
"RmllbGQ9Ik5vT2ZEYXRhU2V0V3JpdGVycyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoN"
"CiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJXcml0ZXJHcm91cFRyYW5zcG9ydERhdGFUeXBl"
"IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+"
"DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJXcml0ZXJHcm91cE1lc3NhZ2VEYXRhVHlw"
"ZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBl"
"Pg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUHViU3ViQ29ubmVjdGlvbkRhdGFUeXBl"
"IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5h"
"bWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRW5hYmxl"
"ZCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUHVibGlz"
"aGVySWQiIFR5cGVOYW1lPSJ1YTpWYXJpYW50IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVHJh"
"bnNwb3J0UHJvZmlsZVVyaSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJBZGRyZXNzIiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTm9PZkNvbm5lY3Rpb25Qcm9wZXJ0aWVzIiBUeXBlTmFtZT0ib3BjOklu"
"dDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQ29ubmVjdGlvblByb3BlcnRpZXMiIFR5cGVO"
"YW1lPSJ0bnM6S2V5VmFsdWVQYWlyIiBMZW5ndGhGaWVsZD0iTm9PZkNvbm5lY3Rpb25Qcm9wZXJ0"
"aWVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVHJhbnNwb3J0U2V0dGluZ3MiIFR5cGVOYW1l"
"PSJ1YTpFeHRlbnNpb25PYmplY3QiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mV3JpdGVy"
"R3JvdXBzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iV3Jp"
"dGVyR3JvdXBzIiBUeXBlTmFtZT0idG5zOldyaXRlckdyb3VwRGF0YVR5cGUiIExlbmd0aEZpZWxk"
"PSJOb09mV3JpdGVyR3JvdXBzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlYWRlckdy"
"b3VwcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlYWRl"
"ckdyb3VwcyIgVHlwZU5hbWU9InRuczpSZWFkZXJHcm91cERhdGFUeXBlIiBMZW5ndGhGaWVsZD0i"
"Tm9PZlJlYWRlckdyb3VwcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpT"
"dHJ1Y3R1cmVkVHlwZSBOYW1lPSJDb25uZWN0aW9uVHJhbnNwb3J0RGF0YVR5cGUiIEJhc2VUeXBl"
"PSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3Bj"
"OlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik5ldHdvcmtBZGRyZXNzRGF0YVR5cGUiIEJhc2VUeXBlPSJ1";
    memcpy(xmlValue.data + 38909, buf_8, 4864);
    char *buf_9 = "YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmV0d29ya0ludGVyZmFj"
"ZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQog"
"IDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iTmV0d29ya0FkZHJlc3NVcmxEYXRhVHlwZSIgQmFz"
"ZVR5cGU9InRuczpOZXR3b3JrQWRkcmVzc0RhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5ldHdvcmtJbnRlcmZhY2UiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiBTb3VyY2VUeXBlPSJ0bnM6"
"TmV0d29ya0FkZHJlc3NEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVybCIgVHlw"
"ZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iUmVhZGVyR3JvdXBEYXRhVHlwZSIgQmFzZVR5cGU9InRuczpQ"
"dWJTdWJHcm91cERhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWUiIFR5cGVOYW1l"
"PSJvcGM6U3RyaW5nIiBTb3VyY2VUeXBlPSJ0bnM6UHViU3ViR3JvdXBEYXRhVHlwZSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkVuYWJsZWQiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgU291cmNl"
"VHlwZT0idG5zOlB1YlN1Ykdyb3VwRGF0YVR5cGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJT"
"ZWN1cml0eU1vZGUiIFR5cGVOYW1lPSJ0bnM6TWVzc2FnZVNlY3VyaXR5TW9kZSIgU291cmNlVHlw"
"ZT0idG5zOlB1YlN1Ykdyb3VwRGF0YVR5cGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1"
"cml0eUdyb3VwSWQiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiBTb3VyY2VUeXBlPSJ0bnM6UHViU3Vi"
"R3JvdXBEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTZWN1cml0eUtleVNl"
"cnZpY2VzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vj"
"dXJpdHlLZXlTZXJ2aWNlcyIgVHlwZU5hbWU9InRuczpFbmRwb2ludERlc2NyaXB0aW9uIiBMZW5n"
"dGhGaWVsZD0iTm9PZlNlY3VyaXR5S2V5U2VydmljZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJNYXhOZXR3b3JrTWVzc2FnZVNpemUiIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBl"
"PSJ0bnM6UHViU3ViR3JvdXBEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZH"
"cm91cFByb3BlcnRpZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJHcm91cFByb3BlcnRpZXMiIFR5cGVOYW1lPSJ0bnM6S2V5VmFsdWVQYWlyIiBMZW5ndGhG"
"aWVsZD0iTm9PZkdyb3VwUHJvcGVydGllcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRyYW5z"
"cG9ydFNldHRpbmdzIiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTWVzc2FnZVNldHRpbmdzIiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkRhdGFTZXRSZWFkZXJzIiBUeXBlTmFtZT0i"
"b3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVNldFJlYWRlcnMiIFR5cGVO"
"YW1lPSJ0bnM6RGF0YVNldFJlYWRlckRhdGFUeXBlIiBMZW5ndGhGaWVsZD0iTm9PZkRhdGFTZXRS"
"ZWFkZXJzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRU"
"eXBlIE5hbWU9IlJlYWRlckdyb3VwVHJhbnNwb3J0RGF0YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRl"
"bnNpb25PYmplY3QiPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVy"
"ZWRUeXBlIE5hbWU9IlJlYWRlckdyb3VwTWVzc2FnZURhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0"
"ZW5zaW9uT2JqZWN0Ij4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1"
"cmVkVHlwZSBOYW1lPSJEYXRhU2V0UmVhZGVyRGF0YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNp"
"b25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmFtZSIgVHlwZU5hbWU9Im9wYzpTdHJp"
"bmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbmFibGVkIiBUeXBlTmFtZT0ib3BjOkJvb2xl"
"YW4iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQdWJsaXNoZXJJZCIgVHlwZU5hbWU9InVhOlZh"
"cmlhbnQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZXJHcm91cElkIiBUeXBlTmFtZT0i"
"b3BjOlVJbnQxNiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFTZXRXcml0ZXJJZCIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MTYiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXRhU2V0TWV0YURh"
"dGEiIFR5cGVOYW1lPSJ0bnM6RGF0YVNldE1ldGFEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkRhdGFTZXRGaWVsZENvbnRlbnRNYXNrIiBUeXBlTmFtZT0idG5zOkRhdGFTZXRGaWVs"
"ZENvbnRlbnRNYXNrIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWVzc2FnZVJlY2VpdmVUaW1l"
"b3V0IiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IktleUZy"
"YW1lQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"SGVhZGVyTGF5b3V0VXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlNlY3VyaXR5TW9kZSIgVHlwZU5hbWU9InRuczpNZXNzYWdlU2VjdXJpdHlNb2RlIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2VjdXJpdHlHcm91cElkIiBUeXBlTmFtZT0ib3BjOlN0"
"cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTZWN1cml0eUtleVNlcnZpY2VzIiBU"
"eXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2VjdXJpdHlLZXlT"
"ZXJ2aWNlcyIgVHlwZU5hbWU9InRuczpFbmRwb2ludERlc2NyaXB0aW9uIiBMZW5ndGhGaWVsZD0i"
"Tm9PZlNlY3VyaXR5S2V5U2VydmljZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRGF0"
"YVNldFJlYWRlclByb3BlcnRpZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJEYXRhU2V0UmVhZGVyUHJvcGVydGllcyIgVHlwZU5hbWU9InRuczpLZXlWYWx1"
"ZVBhaXIiIExlbmd0aEZpZWxkPSJOb09mRGF0YVNldFJlYWRlclByb3BlcnRpZXMiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJUcmFuc3BvcnRTZXR0aW5ncyIgVHlwZU5hbWU9InVhOkV4dGVuc2lv"
"bk9iamVjdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1lc3NhZ2VTZXR0aW5ncyIgVHlwZU5h"
"bWU9InVhOkV4dGVuc2lvbk9iamVjdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN1YnNjcmli"
"ZWREYXRhU2V0IiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiAvPg0KICA8L29wYzpTdHJ1"
"Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkRhdGFTZXRSZWFkZXJU"
"cmFuc3BvcnREYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogIDwvb3Bj"
"OlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRGF0YVNldFJl"
"YWRlck1lc3NhZ2VEYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogIDwv";
    memcpy(xmlValue.data + 43773, buf_9, 4864);
    char *buf_10 = "b3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iU3Vic2Ny"
"aWJlZERhdGFTZXREYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogIDwv"
"b3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVGFyZ2V0"
"VmFyaWFibGVzRGF0YVR5cGUiIEJhc2VUeXBlPSJ0bnM6U3Vic2NyaWJlZERhdGFTZXREYXRhVHlw"
"ZSI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mVGFyZ2V0VmFyaWFibGVzIiBUeXBlTmFtZT0i"
"b3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVGFyZ2V0VmFyaWFibGVzIiBUeXBl"
"TmFtZT0idG5zOkZpZWxkVGFyZ2V0RGF0YVR5cGUiIExlbmd0aEZpZWxkPSJOb09mVGFyZ2V0VmFy"
"aWFibGVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRU"
"eXBlIE5hbWU9IkZpZWxkVGFyZ2V0RGF0YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmpl"
"Y3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVNldEZpZWxkSWQiIFR5cGVOYW1lPSJvcGM6"
"R3VpZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlY2VpdmVySW5kZXhSYW5nZSIgVHlwZU5h"
"bWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUYXJnZXROb2RlSWQiIFR5"
"cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBdHRyaWJ1dGVJZCIg"
"VHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZUluZGV4"
"UmFuZ2UiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iT3Zl"
"cnJpZGVWYWx1ZUhhbmRsaW5nIiBUeXBlTmFtZT0idG5zOk92ZXJyaWRlVmFsdWVIYW5kbGluZyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik92ZXJyaWRlVmFsdWUiIFR5cGVOYW1lPSJ1YTpWYXJp"
"YW50IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBl"
"IE5hbWU9Ik92ZXJyaWRlVmFsdWVIYW5kbGluZyIgTGVuZ3RoSW5CaXRzPSIzMiI+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iRGlzYWJsZWQiIFZhbHVlPSIwIiAvPg0KICAgIDxvcGM6"
"RW51bWVyYXRlZFZhbHVlIE5hbWU9Ikxhc3RVc2FibGVWYWx1ZSIgVmFsdWU9IjEiIC8+DQogICAg"
"PG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iT3ZlcnJpZGVWYWx1ZSIgVmFsdWU9IjIiIC8+DQog"
"IDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iU3Vi"
"c2NyaWJlZERhdGFTZXRNaXJyb3JEYXRhVHlwZSIgQmFzZVR5cGU9InRuczpTdWJzY3JpYmVkRGF0"
"YVNldERhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlBhcmVudE5vZGVOYW1lIiBUeXBl"
"TmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSb2xlUGVybWlz"
"c2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSb2xl"
"UGVybWlzc2lvbnMiIFR5cGVOYW1lPSJ0bnM6Um9sZVBlcm1pc3Npb25UeXBlIiBMZW5ndGhGaWVs"
"ZD0iTm9PZlJvbGVQZXJtaXNzaW9ucyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAg"
"PG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJQdWJTdWJDb25maWd1cmF0aW9uRGF0YVR5cGUiIEJh"
"c2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlB1"
"Ymxpc2hlZERhdGFTZXRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iUHVibGlzaGVkRGF0YVNldHMiIFR5cGVOYW1lPSJ0bnM6UHVibGlzaGVkRGF0YVNldERh"
"dGFUeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlB1Ymxpc2hlZERhdGFTZXRzIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTm9PZkNvbm5lY3Rpb25zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iQ29ubmVjdGlvbnMiIFR5cGVOYW1lPSJ0bnM6UHViU3ViQ29ubmVj"
"dGlvbkRhdGFUeXBlIiBMZW5ndGhGaWVsZD0iTm9PZkNvbm5lY3Rpb25zIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iRW5hYmxlZCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpT"
"dHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9IkRhdGFTZXRPcmRl"
"cmluZ1R5cGUiIExlbmd0aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5h"
"bWU9IlVuZGVmaW5lZCIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFt"
"ZT0iQXNjZW5kaW5nV3JpdGVySWQiIFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZh"
"bHVlIE5hbWU9IkFzY2VuZGluZ1dyaXRlcklkU2luZ2xlIiBWYWx1ZT0iMiIgLz4NCiAgPC9vcGM6"
"RW51bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVkVHlwZSBOYW1lPSJVYWRwTmV0d29y"
"a01lc3NhZ2VDb250ZW50TWFzayIgTGVuZ3RoSW5CaXRzPSIzMiIgSXNPcHRpb25TZXQ9InRydWUi"
"Pg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik5vbmUiIFZhbHVlPSIwIiAvPg0KICAg"
"IDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlB1Ymxpc2hlcklkIiBWYWx1ZT0iMSIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJHcm91cEhlYWRlciIgVmFsdWU9IjIiIC8+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iV3JpdGVyR3JvdXBJZCIgVmFsdWU9IjQiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iR3JvdXBWZXJzaW9uIiBWYWx1ZT0iOCIg"
"Lz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOZXR3b3JrTWVzc2FnZU51bWJlciIg"
"VmFsdWU9IjE2IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNlcXVlbmNlTnVt"
"YmVyIiBWYWx1ZT0iMzIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUGF5bG9h"
"ZEhlYWRlciIgVmFsdWU9IjY0IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlRp"
"bWVzdGFtcCIgVmFsdWU9IjEyOCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJQ"
"aWNvU2Vjb25kcyIgVmFsdWU9IjI1NiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1l"
"PSJEYXRhU2V0Q2xhc3NJZCIgVmFsdWU9IjUxMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1"
"ZSBOYW1lPSJQcm9tb3RlZEZpZWxkcyIgVmFsdWU9IjEwMjQiIC8+DQogIDwvb3BjOkVudW1lcmF0"
"ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVWFkcFdyaXRlckdyb3VwTWVz"
"c2FnZURhdGFUeXBlIiBCYXNlVHlwZT0idG5zOldyaXRlckdyb3VwTWVzc2FnZURhdGFUeXBlIj4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ikdyb3VwVmVyc2lvbiIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXRhU2V0T3JkZXJpbmciIFR5cGVOYW1lPSJ0bnM6"
"RGF0YVNldE9yZGVyaW5nVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5ldHdvcmtNZXNz"
"YWdlQ29udGVudE1hc2siIFR5cGVOYW1lPSJ0bnM6VWFkcE5ldHdvcmtNZXNzYWdlQ29udGVudE1h";
    memcpy(xmlValue.data + 48637, buf_10, 4864);
    char *buf_11 = "c2siIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTYW1wbGluZ09mZnNldCIgVHlwZU5hbWU9Im9w"
"YzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUHVibGlzaGluZ09mZnNldCIg"
"VHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlB1Ymxpc2hpbmdP"
"ZmZzZXQiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiBMZW5ndGhGaWVsZD0iTm9PZlB1Ymxpc2hpbmdP"
"ZmZzZXQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5"
"cGUgTmFtZT0iVWFkcERhdGFTZXRNZXNzYWdlQ29udGVudE1hc2siIExlbmd0aEluQml0cz0iMzIi"
"IElzT3B0aW9uU2V0PSJ0cnVlIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOb25l"
"IiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJUaW1lc3RhbXAi"
"IFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlBpY29TZWNvbmRz"
"IiBWYWx1ZT0iMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJTdGF0dXMiIFZh"
"bHVlPSI0IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik1ham9yVmVyc2lvbiIg"
"VmFsdWU9IjgiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTWlub3JWZXJzaW9u"
"IiBWYWx1ZT0iMTYiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU2VxdWVuY2VO"
"dW1iZXIiIFZhbHVlPSIzMiIgLz4NCiAgPC9vcGM6RW51bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpT"
"dHJ1Y3R1cmVkVHlwZSBOYW1lPSJVYWRwRGF0YVNldFdyaXRlck1lc3NhZ2VEYXRhVHlwZSIgQmFz"
"ZVR5cGU9InRuczpEYXRhU2V0V3JpdGVyTWVzc2FnZURhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkRhdGFTZXRNZXNzYWdlQ29udGVudE1hc2siIFR5cGVOYW1lPSJ0bnM6VWFkcERhdGFT"
"ZXRNZXNzYWdlQ29udGVudE1hc2siIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDb25maWd1cmVk"
"U2l6ZSIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOZXR3"
"b3JrTWVzc2FnZU51bWJlciIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJEYXRhU2V0T2Zmc2V0IiBUeXBlTmFtZT0ib3BjOlVJbnQxNiIgLz4NCiAgPC9vcGM6"
"U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJVYWRwRGF0YVNl"
"dFJlYWRlck1lc3NhZ2VEYXRhVHlwZSIgQmFzZVR5cGU9InRuczpEYXRhU2V0UmVhZGVyTWVzc2Fn"
"ZURhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ikdyb3VwVmVyc2lvbiIgVHlwZU5hbWU9"
"Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOZXR3b3JrTWVzc2FnZU51bWJl"
"ciIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXRhU2V0"
"T2Zmc2V0IiBUeXBlTmFtZT0ib3BjOlVJbnQxNiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRh"
"dGFTZXRDbGFzc0lkIiBUeXBlTmFtZT0ib3BjOkd1aWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJOZXR3b3JrTWVzc2FnZUNvbnRlbnRNYXNrIiBUeXBlTmFtZT0idG5zOlVhZHBOZXR3b3JrTWVz"
"c2FnZUNvbnRlbnRNYXNrIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVNldE1lc3NhZ2VD"
"b250ZW50TWFzayIgVHlwZU5hbWU9InRuczpVYWRwRGF0YVNldE1lc3NhZ2VDb250ZW50TWFzayIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlB1Ymxpc2hpbmdJbnRlcnZhbCIgVHlwZU5hbWU9Im9w"
"YzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWNlaXZlT2Zmc2V0IiBUeXBlTmFt"
"ZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlByb2Nlc3NpbmdPZmZzZXQi"
"IFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9Ikpzb25OZXR3b3JrTWVzc2FnZUNvbnRlbnRNYXNrIiBM"
"ZW5ndGhJbkJpdHM9IjMyIiBJc09wdGlvblNldD0idHJ1ZSI+DQogICAgPG9wYzpFbnVtZXJhdGVk"
"VmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUg"
"TmFtZT0iTmV0d29ya01lc3NhZ2VIZWFkZXIiIFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVy"
"YXRlZFZhbHVlIE5hbWU9IkRhdGFTZXRNZXNzYWdlSGVhZGVyIiBWYWx1ZT0iMiIgLz4NCiAgICA8"
"b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJTaW5nbGVEYXRhU2V0TWVzc2FnZSIgVmFsdWU9IjQi"
"IC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUHVibGlzaGVySWQiIFZhbHVlPSI4"
"IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkRhdGFTZXRDbGFzc0lkIiBWYWx1"
"ZT0iMTYiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUmVwbHlUbyIgVmFsdWU9"
"IjMyIiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9Ikpzb25Xcml0ZXJHcm91cE1lc3NhZ2VEYXRhVHlwZSIgQmFzZVR5cGU9InRuczpXcml0"
"ZXJHcm91cE1lc3NhZ2VEYXRhVHlwZSI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOZXR3b3JrTWVz"
"c2FnZUNvbnRlbnRNYXNrIiBUeXBlTmFtZT0idG5zOkpzb25OZXR3b3JrTWVzc2FnZUNvbnRlbnRN"
"YXNrIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBl"
"IE5hbWU9Ikpzb25EYXRhU2V0TWVzc2FnZUNvbnRlbnRNYXNrIiBMZW5ndGhJbkJpdHM9IjMyIiBJ"
"c09wdGlvblNldD0idHJ1ZSI+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm9uZSIg"
"VmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iRGF0YVNldFdyaXRl"
"cklkIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJNZXRhRGF0"
"YVZlcnNpb24iIFZhbHVlPSIyIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNl"
"cXVlbmNlTnVtYmVyIiBWYWx1ZT0iNCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1l"
"PSJUaW1lc3RhbXAiIFZhbHVlPSI4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9"
"IlN0YXR1cyIgVmFsdWU9IjE2IiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3Bj"
"OlN0cnVjdHVyZWRUeXBlIE5hbWU9Ikpzb25EYXRhU2V0V3JpdGVyTWVzc2FnZURhdGFUeXBlIiBC"
"YXNlVHlwZT0idG5zOkRhdGFTZXRXcml0ZXJNZXNzYWdlRGF0YVR5cGUiPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iRGF0YVNldE1lc3NhZ2VDb250ZW50TWFzayIgVHlwZU5hbWU9InRuczpKc29uRGF0"
"YVNldE1lc3NhZ2VDb250ZW50TWFzayIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAg"
"PG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJKc29uRGF0YVNldFJlYWRlck1lc3NhZ2VEYXRhVHlw"
"ZSIgQmFzZVR5cGU9InRuczpEYXRhU2V0UmVhZGVyTWVzc2FnZURhdGFUeXBlIj4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5ldHdvcmtNZXNzYWdlQ29udGVudE1hc2siIFR5cGVOYW1lPSJ0bnM6SnNv";
    memcpy(xmlValue.data + 53501, buf_11, 4864);
    char *buf_12 = "bk5ldHdvcmtNZXNzYWdlQ29udGVudE1hc2siIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXRh"
"U2V0TWVzc2FnZUNvbnRlbnRNYXNrIiBUeXBlTmFtZT0idG5zOkpzb25EYXRhU2V0TWVzc2FnZUNv"
"bnRlbnRNYXNrIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVy"
"ZWRUeXBlIE5hbWU9IkRhdGFncmFtQ29ubmVjdGlvblRyYW5zcG9ydERhdGFUeXBlIiBCYXNlVHlw"
"ZT0idG5zOkNvbm5lY3Rpb25UcmFuc3BvcnREYXRhVHlwZSI+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJEaXNjb3ZlcnlBZGRyZXNzIiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiAvPg0KICA8"
"L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkRhdGFn"
"cmFtV3JpdGVyR3JvdXBUcmFuc3BvcnREYXRhVHlwZSIgQmFzZVR5cGU9InRuczpXcml0ZXJHcm91"
"cFRyYW5zcG9ydERhdGFUeXBlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1lc3NhZ2VSZXBlYXRD"
"b3VudCIgVHlwZU5hbWU9Im9wYzpCeXRlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWVzc2Fn"
"ZVJlcGVhdERlbGF5IiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJl"
"ZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJCcm9rZXJDb25uZWN0aW9uVHJh"
"bnNwb3J0RGF0YVR5cGUiIEJhc2VUeXBlPSJ0bnM6Q29ubmVjdGlvblRyYW5zcG9ydERhdGFUeXBl"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc291cmNlVXJpIiBUeXBlTmFtZT0ib3BjOlN0cmlu"
"ZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkF1dGhlbnRpY2F0aW9uUHJvZmlsZVVyaSIgVHlw"
"ZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"RW51bWVyYXRlZFR5cGUgTmFtZT0iQnJva2VyVHJhbnNwb3J0UXVhbGl0eU9mU2VydmljZSIgTGVu"
"Z3RoSW5CaXRzPSIzMiI+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm90U3BlY2lm"
"aWVkIiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJCZXN0RWZm"
"b3J0IiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJBdExlYXN0"
"T25jZSIgVmFsdWU9IjIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQXRNb3N0"
"T25jZSIgVmFsdWU9IjMiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iRXhhY3Rs"
"eU9uY2UiIFZhbHVlPSI0IiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IkJyb2tlcldyaXRlckdyb3VwVHJhbnNwb3J0RGF0YVR5cGUiIEJh"
"c2VUeXBlPSJ0bnM6V3JpdGVyR3JvdXBUcmFuc3BvcnREYXRhVHlwZSI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJRdWV1ZU5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVzb3VyY2VVcmkiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iQXV0aGVudGljYXRpb25Qcm9maWxlVXJpIiBUeXBlTmFtZT0ib3BjOlN0cmlu"
"ZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RlZERlbGl2ZXJ5R3VhcmFudGVlIiBU"
"eXBlTmFtZT0idG5zOkJyb2tlclRyYW5zcG9ydFF1YWxpdHlPZlNlcnZpY2UiIC8+DQogIDwvb3Bj"
"OlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQnJva2VyRGF0"
"YVNldFdyaXRlclRyYW5zcG9ydERhdGFUeXBlIiBCYXNlVHlwZT0idG5zOkRhdGFTZXRXcml0ZXJU"
"cmFuc3BvcnREYXRhVHlwZSI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJRdWV1ZU5hbWUiIFR5cGVO"
"YW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzb3VyY2VVcmkiIFR5"
"cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQXV0aGVudGljYXRp"
"b25Qcm9maWxlVXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlcXVlc3RlZERlbGl2ZXJ5R3VhcmFudGVlIiBUeXBlTmFtZT0idG5zOkJyb2tlclRyYW5z"
"cG9ydFF1YWxpdHlPZlNlcnZpY2UiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNZXRhRGF0YVF1"
"ZXVlTmFtZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJN"
"ZXRhRGF0YVVwZGF0ZVRpbWUiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICA8L29wYzpTdHJ1"
"Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkJyb2tlckRhdGFTZXRS"
"ZWFkZXJUcmFuc3BvcnREYXRhVHlwZSIgQmFzZVR5cGU9InRuczpEYXRhU2V0UmVhZGVyVHJhbnNw"
"b3J0RGF0YVR5cGUiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUXVldWVOYW1lIiBUeXBlTmFtZT0i"
"b3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc291cmNlVXJpIiBUeXBlTmFt"
"ZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkF1dGhlbnRpY2F0aW9uUHJv"
"ZmlsZVVyaSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJS"
"ZXF1ZXN0ZWREZWxpdmVyeUd1YXJhbnRlZSIgVHlwZU5hbWU9InRuczpCcm9rZXJUcmFuc3BvcnRR"
"dWFsaXR5T2ZTZXJ2aWNlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWV0YURhdGFRdWV1ZU5h"
"bWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0K"
"ICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9IkRpYWdub3N0aWNzTGV2ZWwiIExlbmd0aEluQml0"
"cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkJhc2ljIiBWYWx1ZT0iMCIg"
"Lz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJBZHZhbmNlZCIgVmFsdWU9IjEiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSW5mbyIgVmFsdWU9IjIiIC8+DQogICAg"
"PG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTG9nIiBWYWx1ZT0iMyIgLz4NCiAgICA8b3BjOkVu"
"dW1lcmF0ZWRWYWx1ZSBOYW1lPSJEZWJ1ZyIgVmFsdWU9IjQiIC8+DQogIDwvb3BjOkVudW1lcmF0"
"ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iUHViU3ViRGlhZ25vc3RpY3ND"
"b3VudGVyQ2xhc3NpZmljYXRpb24iIExlbmd0aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVy"
"YXRlZFZhbHVlIE5hbWU9IkluZm9ybWF0aW9uIiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1l"
"cmF0ZWRWYWx1ZSBOYW1lPSJFcnJvciIgVmFsdWU9IjEiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRU"
"eXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQWxpYXNOYW1lRGF0YVR5cGUiIEJh"
"c2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWxpYXNO"
"YW1lIiBUeXBlTmFtZT0idWE6UXVhbGlmaWVkTmFtZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5vT2ZSZWZlcmVuY2VkTm9kZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJSZWZlcmVuY2VkTm9kZXMiIFR5cGVOYW1lPSJ1YTpFeHBhbmRlZE5vZGVJZCIg";
    memcpy(xmlValue.data + 58365, buf_12, 4864);
    char *buf_13 = "TGVuZ3RoRmllbGQ9Ik5vT2ZSZWZlcmVuY2VkTm9kZXMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRU"
"eXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iSWRUeXBlIiBMZW5ndGhJbkJpdHM9"
"IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOdW1lcmljIiBWYWx1ZT0iMCIg"
"Lz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJTdHJpbmciIFZhbHVlPSIxIiAvPg0K"
"ICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ikd1aWQiIFZhbHVlPSIyIiAvPg0KICAgIDxv"
"cGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik9wYXF1ZSIgVmFsdWU9IjMiIC8+DQogIDwvb3BjOkVu"
"dW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iTm9kZUNsYXNzIiBM"
"ZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJVbnNwZWNp"
"ZmllZCIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iT2JqZWN0"
"IiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJWYXJpYWJsZSIg"
"VmFsdWU9IjIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTWV0aG9kIiBWYWx1"
"ZT0iNCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJPYmplY3RUeXBlIiBWYWx1"
"ZT0iOCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJWYXJpYWJsZVR5cGUiIFZh"
"bHVlPSIxNiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJSZWZlcmVuY2VUeXBl"
"IiBWYWx1ZT0iMzIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iRGF0YVR5cGUi"
"IFZhbHVlPSI2NCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJWaWV3IiBWYWx1"
"ZT0iMTI4IiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRU"
"eXBlIE5hbWU9IlBlcm1pc3Npb25UeXBlIiBMZW5ndGhJbkJpdHM9IjMyIiBJc09wdGlvblNldD0i"
"dHJ1ZSI+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQnJvd3NlIiBWYWx1ZT0iMSIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJSZWFkUm9sZVBlcm1pc3Npb25zIiBWYWx1ZT0i"
"MiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJXcml0ZUF0dHJpYnV0ZSIgVmFs"
"dWU9IjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iV3JpdGVSb2xlUGVybWlz"
"c2lvbnMiIFZhbHVlPSI4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IldyaXRl"
"SGlzdG9yaXppbmciIFZhbHVlPSIxNiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1l"
"PSJSZWFkIiBWYWx1ZT0iMzIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iV3Jp"
"dGUiIFZhbHVlPSI2NCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJSZWFkSGlz"
"dG9yeSIgVmFsdWU9IjEyOCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJJbnNl"
"cnRIaXN0b3J5IiBWYWx1ZT0iMjU2IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9"
"Ik1vZGlmeUhpc3RvcnkiIFZhbHVlPSI1MTIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUg"
"TmFtZT0iRGVsZXRlSGlzdG9yeSIgVmFsdWU9IjEwMjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVk"
"VmFsdWUgTmFtZT0iUmVjZWl2ZUV2ZW50cyIgVmFsdWU9IjIwNDgiIC8+DQogICAgPG9wYzpFbnVt"
"ZXJhdGVkVmFsdWUgTmFtZT0iQ2FsbCIgVmFsdWU9IjQwOTYiIC8+DQogICAgPG9wYzpFbnVtZXJh"
"dGVkVmFsdWUgTmFtZT0iQWRkUmVmZXJlbmNlIiBWYWx1ZT0iODE5MiIgLz4NCiAgICA8b3BjOkVu"
"dW1lcmF0ZWRWYWx1ZSBOYW1lPSJSZW1vdmVSZWZlcmVuY2UiIFZhbHVlPSIxNjM4NCIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJEZWxldGVOb2RlIiBWYWx1ZT0iMzI3NjgiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQWRkTm9kZSIgVmFsdWU9IjY1NTM2IiAv"
"Pg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9"
"IkFjY2Vzc0xldmVsVHlwZSIgTGVuZ3RoSW5CaXRzPSI4IiBJc09wdGlvblNldD0idHJ1ZSI+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQ3VycmVudFJlYWQiIFZhbHVlPSIxIiAvPg0KICAgIDxv"
"cGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkN1cnJlbnRXcml0ZSIgVmFsdWU9IjIiIC8+DQogICAg"
"PG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSGlzdG9yeVJlYWQiIFZhbHVlPSI0IiAvPg0KICAg"
"IDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ikhpc3RvcnlXcml0ZSIgVmFsdWU9IjgiIC8+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU2VtYW50aWNDaGFuZ2UiIFZhbHVlPSIxNiIg"
"Lz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJTdGF0dXNXcml0ZSIgVmFsdWU9IjMy"
"IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlRpbWVzdGFtcFdyaXRlIiBWYWx1"
"ZT0iNjQiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5"
"cGUgTmFtZT0iQWNjZXNzTGV2ZWxFeFR5cGUiIExlbmd0aEluQml0cz0iMzIiIElzT3B0aW9uU2V0"
"PSJ0cnVlIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOb25lIiBWYWx1ZT0iMCIg"
"Lz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJDdXJyZW50UmVhZCIgVmFsdWU9IjEi"
"IC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQ3VycmVudFdyaXRlIiBWYWx1ZT0i"
"MiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJIaXN0b3J5UmVhZCIgVmFsdWU9"
"IjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSGlzdG9yeVdyaXRlIiBWYWx1"
"ZT0iOCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJTZW1hbnRpY0NoYW5nZSIg"
"VmFsdWU9IjE2IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlN0YXR1c1dyaXRl"
"IiBWYWx1ZT0iMzIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVGltZXN0YW1w"
"V3JpdGUiIFZhbHVlPSI2NCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOb25h"
"dG9taWNSZWFkIiBWYWx1ZT0iMjU2IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9"
"Ik5vbmF0b21pY1dyaXRlIiBWYWx1ZT0iNTEyIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVl"
"IE5hbWU9IldyaXRlRnVsbEFycmF5T25seSIgVmFsdWU9IjEwMjQiIC8+DQogICAgPG9wYzpFbnVt"
"ZXJhdGVkVmFsdWUgTmFtZT0iTm9TdWJEYXRhVHlwZXMiIFZhbHVlPSIyMDQ4IiAvPg0KICA8L29w"
"YzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9IkV2ZW50Tm90"
"aWZpZXJUeXBlIiBMZW5ndGhJbkJpdHM9IjgiIElzT3B0aW9uU2V0PSJ0cnVlIj4NCiAgICA8b3Bj";
    memcpy(xmlValue.data + 63229, buf_13, 4864);
    char *buf_14 = "OkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOb25lIiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1l"
"cmF0ZWRWYWx1ZSBOYW1lPSJTdWJzY3JpYmVUb0V2ZW50cyIgVmFsdWU9IjEiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSGlzdG9yeVJlYWQiIFZhbHVlPSI0IiAvPg0KICAgIDxv"
"cGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ikhpc3RvcnlXcml0ZSIgVmFsdWU9IjgiIC8+DQogIDwv"
"b3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iQWNjZXNz"
"UmVzdHJpY3Rpb25UeXBlIiBMZW5ndGhJbkJpdHM9IjE2IiBJc09wdGlvblNldD0idHJ1ZSI+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU2lnbmluZ1JlcXVpcmVkIiBWYWx1ZT0iMSIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJFbmNyeXB0aW9uUmVxdWlyZWQiIFZhbHVlPSIy"
"IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNlc3Npb25SZXF1aXJlZCIgVmFs"
"dWU9IjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQXBwbHlSZXN0cmljdGlv"
"bnNUb0Jyb3dzZSIgVmFsdWU9IjgiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxv"
"cGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUm9sZVBlcm1pc3Npb25UeXBlIiBCYXNlVHlwZT0idWE6"
"RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJvbGVJZCIgVHlwZU5hbWU9"
"InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlBlcm1pc3Npb25zIiBUeXBlTmFt"
"ZT0idG5zOlBlcm1pc3Npb25UeXBlIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9IlN0cnVjdHVyZVR5cGUiIExlbmd0aEluQml0cz0iMzIi"
"Pg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlN0cnVjdHVyZSIgVmFsdWU9IjAiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU3RydWN0dXJlV2l0aE9wdGlvbmFsRmll"
"bGRzIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJVbmlvbiIg"
"VmFsdWU9IjIiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJl"
"ZFR5cGUgTmFtZT0iU3RydWN0dXJlRmllbGQiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3Qi"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmFtZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5hbWU9InVhOkxvY2FsaXplZFRl"
"eHQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXRhVHlwZSIgVHlwZU5hbWU9InVhOk5vZGVJ"
"ZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlZhbHVlUmFuayIgVHlwZU5hbWU9Im9wYzpJbnQz"
"MiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZBcnJheURpbWVuc2lvbnMiIFR5cGVOYW1l"
"PSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBcnJheURpbWVuc2lvbnMiIFR5"
"cGVOYW1lPSJvcGM6VUludDMyIiBMZW5ndGhGaWVsZD0iTm9PZkFycmF5RGltZW5zaW9ucyIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1heFN0cmluZ0xlbmd0aCIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJc09wdGlvbmFsIiBUeXBlTmFtZT0ib3BjOkJv"
"b2xlYW4iIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iU3RydWN0dXJlRGVmaW5pdGlvbiIgQmFzZVR5cGU9InRuczpEYXRhVHlwZURlZmlu"
"aXRpb24iPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVmYXVsdEVuY29kaW5nSWQiIFR5cGVOYW1l"
"PSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJCYXNlRGF0YVR5cGUiIFR5cGVO"
"YW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdHJ1Y3R1cmVUeXBlIiBU"
"eXBlTmFtZT0idG5zOlN0cnVjdHVyZVR5cGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09m"
"RmllbGRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRmll"
"bGRzIiBUeXBlTmFtZT0idG5zOlN0cnVjdHVyZUZpZWxkIiBMZW5ndGhGaWVsZD0iTm9PZkZpZWxk"
"cyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBO"
"YW1lPSJFbnVtRGVmaW5pdGlvbiIgQmFzZVR5cGU9InRuczpEYXRhVHlwZURlZmluaXRpb24iPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkZpZWxkcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkZpZWxkcyIgVHlwZU5hbWU9InRuczpFbnVtRmllbGQiIExl"
"bmd0aEZpZWxkPSJOb09mRmllbGRzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik5vZGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmpl"
"Y3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUlkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUNsYXNzIiBUeXBlTmFtZT0idG5zOk5vZGVDbGFz"
"cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZU5hbWUiIFR5cGVOYW1lPSJ1YTpRdWFs"
"aWZpZWROYW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1l"
"PSJ1YTpMb2NhbGl6ZWRUZXh0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVzY3JpcHRpb24i"
"IFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iV3Jp"
"dGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVz"
"ZXJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iTm9PZlJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9InRuczpSb2xlUGVybWlzc2lv"
"blR5cGUiIExlbmd0aEZpZWxkPSJOb09mUm9sZVBlcm1pc3Npb25zIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iTm9PZlVzZXJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VyUm9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0idG5z"
"OlJvbGVQZXJtaXNzaW9uVHlwZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZVc2VyUm9sZVBlcm1pc3Npb25z"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWNjZXNzUmVzdHJpY3Rpb25zIiBUeXBlTmFtZT0i"
"b3BjOlVJbnQxNiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZWZlcmVuY2VzIiBUeXBl"
"TmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVmZXJlbmNlcyIgVHlw"
"ZU5hbWU9InRuczpSZWZlcmVuY2VOb2RlIiBMZW5ndGhGaWVsZD0iTm9PZlJlZmVyZW5jZXMiIC8+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i";
    memcpy(xmlValue.data + 68093, buf_14, 4864);
    char *buf_15 = "SW5zdGFuY2VOb2RlIiBCYXNlVHlwZT0idG5zOk5vZGUiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Tm9kZUlkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVDbGFzcyIgVHlwZU5hbWU9InRuczpOb2RlQ2xhc3MiIFNv"
"dXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQnJvd3NlTmFtZSIg"
"VHlwZU5hbWU9InVhOlF1YWxpZmllZE5hbWUiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0"
"IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0"
"aW9uIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBT"
"b3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZXJXcml0ZU1h"
"c2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJ0bnM6"
"Um9sZVBlcm1pc3Npb25UeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlJvbGVQZXJtaXNzaW9ucyIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZVc2VyUm9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0i"
"b3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlclJvbGVQZXJtaXNzaW9ucyIg"
"VHlwZU5hbWU9InRuczpSb2xlUGVybWlzc2lvblR5cGUiIExlbmd0aEZpZWxkPSJOb09mVXNlclJv"
"bGVQZXJtaXNzaW9ucyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFjY2Vzc1Jlc3RyaWN0aW9u"
"cyIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTm9PZlJlZmVyZW5jZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VzIiBUeXBlTmFtZT0idG5zOlJlZmVyZW5jZU5v"
"ZGUiIExlbmd0aEZpZWxkPSJOb09mUmVmZXJlbmNlcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5"
"cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJUeXBlTm9kZSIgQmFzZVR5cGU9InRu"
"czpOb2RlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVJZCIgVHlwZU5hbWU9InVhOk5vZGVJ"
"ZCIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlQ2xh"
"c3MiIFR5cGVOYW1lPSJ0bnM6Tm9kZUNsYXNzIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZU5hbWUiIFR5cGVOYW1lPSJ1YTpRdWFsaWZpZWROYW1l"
"IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpc3BsYXlO"
"YW1lIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5hbWU9InVhOkxvY2FsaXpl"
"ZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iV3Jp"
"dGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VyV3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIg"
"U291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUm9sZVBl"
"cm1pc3Npb25zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Um9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0idG5zOlJvbGVQZXJtaXNzaW9uVHlwZSIgTGVuZ3Ro"
"RmllbGQ9Ik5vT2ZSb2xlUGVybWlzc2lvbnMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09m"
"VXNlclJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlVzZXJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJ0bnM6Um9sZVBlcm1pc3Np"
"b25UeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlVzZXJSb2xlUGVybWlzc2lvbnMiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJBY2Nlc3NSZXN0cmljdGlvbnMiIFR5cGVOYW1lPSJvcGM6VUludDE2IiBT"
"b3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZWZlcmVu"
"Y2VzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVmZXJl"
"bmNlcyIgVHlwZU5hbWU9InRuczpSZWZlcmVuY2VOb2RlIiBMZW5ndGhGaWVsZD0iTm9PZlJlZmVy"
"ZW5jZXMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iT2JqZWN0Tm9kZSIgQmFzZVR5cGU9InRuczpJbnN0YW5jZU5vZGUiPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTm9kZUlkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiBTb3VyY2VUeXBlPSJ0"
"bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVDbGFzcyIgVHlwZU5hbWU9InRu"
"czpOb2RlQ2xhc3MiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iQnJvd3NlTmFtZSIgVHlwZU5hbWU9InVhOlF1YWxpZmllZE5hbWUiIFNvdXJjZVR5cGU9InRu"
"czpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1lPSJ1"
"YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlw"
"ZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZU1hc2siIFR5cGVOYW1l"
"PSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlVzZXJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6"
"Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSb2xlUGVybWlzc2lvbnMiIFR5cGVO"
"YW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSb2xlUGVybWlzc2lvbnMi"
"IFR5cGVOYW1lPSJ0bnM6Um9sZVBlcm1pc3Npb25UeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlJvbGVQ"
"ZXJtaXNzaW9ucyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZVc2VyUm9sZVBlcm1pc3Np"
"b25zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlclJv"
"bGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9InRuczpSb2xlUGVybWlzc2lvblR5cGUiIExlbmd0aEZp"
"ZWxkPSJOb09mVXNlclJvbGVQZXJtaXNzaW9ucyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFj"
"Y2Vzc1Jlc3RyaWN0aW9ucyIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIFNvdXJjZVR5cGU9InRuczpO";
    memcpy(xmlValue.data + 72957, buf_15, 4864);
    char *buf_16 = "b2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlZmVyZW5jZXMiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VzIiBUeXBlTmFtZT0i"
"dG5zOlJlZmVyZW5jZU5vZGUiIExlbmd0aEZpZWxkPSJOb09mUmVmZXJlbmNlcyIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkV2ZW50Tm90aWZpZXIiIFR5cGVOYW1lPSJvcGM6Qnl0ZSIgLz4NCiAg"
"PC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJPYmpl"
"Y3RUeXBlTm9kZSIgQmFzZVR5cGU9InRuczpUeXBlTm9kZSI+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUNsYXNzIiBUeXBlTmFtZT0idG5zOk5vZGVDbGFzcyIg"
"U291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJCcm93c2VOYW1l"
"IiBUeXBlTmFtZT0idWE6UXVhbGlmaWVkTmFtZSIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNwbGF5TmFtZSIgVHlwZU5hbWU9InVhOkxvY2FsaXplZFRl"
"eHQiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVzY3Jp"
"cHRpb24iIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IldyaXRlTWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlcldyaXRl"
"TWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iTm9PZlJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQz"
"MiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9InRu"
"czpSb2xlUGVybWlzc2lvblR5cGUiIExlbmd0aEZpZWxkPSJOb09mUm9sZVBlcm1pc3Npb25zIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlVzZXJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1l"
"PSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VyUm9sZVBlcm1pc3Npb25z"
"IiBUeXBlTmFtZT0idG5zOlJvbGVQZXJtaXNzaW9uVHlwZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZVc2Vy"
"Um9sZVBlcm1pc3Npb25zIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWNjZXNzUmVzdHJpY3Rp"
"b25zIiBUeXBlTmFtZT0ib3BjOlVJbnQxNiIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJOb09mUmVmZXJlbmNlcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlZmVyZW5jZXMiIFR5cGVOYW1lPSJ0bnM6UmVmZXJlbmNl"
"Tm9kZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZWZlcmVuY2VzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iSXNBYnN0cmFjdCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1"
"cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlZhcmlhYmxlTm9kZSIgQmFz"
"ZVR5cGU9InRuczpJbnN0YW5jZU5vZGUiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUlkIiBU"
"eXBlTmFtZT0idWE6Tm9kZUlkIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ik5vZGVDbGFzcyIgVHlwZU5hbWU9InRuczpOb2RlQ2xhc3MiIFNvdXJjZVR5cGU9"
"InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQnJvd3NlTmFtZSIgVHlwZU5hbWU9"
"InVhOlF1YWxpZmllZE5hbWUiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VU"
"eXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBl"
"TmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBl"
"PSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZXJXcml0ZU1hc2siIFR5cGVO"
"YW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9Ik5vT2ZSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJ0bnM6Um9sZVBlcm1p"
"c3Npb25UeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlJvbGVQZXJtaXNzaW9ucyIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5vT2ZVc2VyUm9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0ib3BjOkludDMy"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlclJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9"
"InRuczpSb2xlUGVybWlzc2lvblR5cGUiIExlbmd0aEZpZWxkPSJOb09mVXNlclJvbGVQZXJtaXNz"
"aW9ucyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFjY2Vzc1Jlc3RyaWN0aW9ucyIgVHlwZU5h"
"bWU9Im9wYzpVSW50MTYiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iTm9PZlJlZmVyZW5jZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJSZWZlcmVuY2VzIiBUeXBlTmFtZT0idG5zOlJlZmVyZW5jZU5vZGUiIExlbmd0"
"aEZpZWxkPSJOb09mUmVmZXJlbmNlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlZhbHVlIiBU"
"eXBlTmFtZT0idWE6VmFyaWFudCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFUeXBlIiBU"
"eXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVmFsdWVSYW5rIiBU"
"eXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkFycmF5RGlt"
"ZW5zaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFy"
"cmF5RGltZW5zaW9ucyIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIExlbmd0aEZpZWxkPSJOb09mQXJy"
"YXlEaW1lbnNpb25zIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWNjZXNzTGV2ZWwiIFR5cGVO"
"YW1lPSJvcGM6Qnl0ZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZXJBY2Nlc3NMZXZlbCIg"
"VHlwZU5hbWU9Im9wYzpCeXRlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWluaW11bVNhbXBs"
"aW5nSW50ZXJ2YWwiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iSGlzdG9yaXppbmciIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkFjY2Vzc0xldmVsRXgiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICA8L29wYzpT"
"dHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlZhcmlhYmxlVHlw"
"ZU5vZGUiIEJhc2VUeXBlPSJ0bnM6VHlwZU5vZGUiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9k";
    memcpy(xmlValue.data + 77821, buf_16, 4864);
    char *buf_17 = "ZUlkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9Ik5vZGVDbGFzcyIgVHlwZU5hbWU9InRuczpOb2RlQ2xhc3MiIFNvdXJj"
"ZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQnJvd3NlTmFtZSIgVHlw"
"ZU5hbWU9InVhOlF1YWxpZmllZE5hbWUiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBT"
"b3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0aW9u"
"IiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3Vy"
"Y2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZXJXcml0ZU1hc2si"
"IFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5vT2ZSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJ0bnM6Um9s"
"ZVBlcm1pc3Npb25UeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlJvbGVQZXJtaXNzaW9ucyIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZVc2VyUm9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlclJvbGVQZXJtaXNzaW9ucyIgVHlw"
"ZU5hbWU9InRuczpSb2xlUGVybWlzc2lvblR5cGUiIExlbmd0aEZpZWxkPSJOb09mVXNlclJvbGVQ"
"ZXJtaXNzaW9ucyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFjY2Vzc1Jlc3RyaWN0aW9ucyIg"
"VHlwZU5hbWU9Im9wYzpVSW50MTYiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTm9PZlJlZmVyZW5jZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VzIiBUeXBlTmFtZT0idG5zOlJlZmVyZW5jZU5vZGUi"
"IExlbmd0aEZpZWxkPSJOb09mUmVmZXJlbmNlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlZh"
"bHVlIiBUeXBlTmFtZT0idWE6VmFyaWFudCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFU"
"eXBlIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVmFsdWVS"
"YW5rIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkFy"
"cmF5RGltZW5zaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IkFycmF5RGltZW5zaW9ucyIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIExlbmd0aEZpZWxkPSJO"
"b09mQXJyYXlEaW1lbnNpb25zIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSXNBYnN0cmFjdCIg"
"VHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlZmVyZW5jZVR5cGVOb2RlIiBCYXNlVHlwZT0idG5z"
"OlR5cGVOb2RlIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVJZCIgVHlwZU5hbWU9InVhOk5v"
"ZGVJZCIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2Rl"
"Q2xhc3MiIFR5cGVOYW1lPSJ0bnM6Tm9kZUNsYXNzIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZU5hbWUiIFR5cGVOYW1lPSJ1YTpRdWFsaWZpZWRO"
"YW1lIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpc3Bs"
"YXlOYW1lIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5zOk5vZGUi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5hbWU9InVhOkxvY2Fs"
"aXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"V3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VyV3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQz"
"MiIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUm9s"
"ZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iUm9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0idG5zOlJvbGVQZXJtaXNzaW9uVHlwZSIgTGVu"
"Z3RoRmllbGQ9Ik5vT2ZSb2xlUGVybWlzc2lvbnMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJO"
"b09mVXNlclJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlVzZXJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJ0bnM6Um9sZVBlcm1p"
"c3Npb25UeXBlIiBMZW5ndGhGaWVsZD0iTm9PZlVzZXJSb2xlUGVybWlzc2lvbnMiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJBY2Nlc3NSZXN0cmljdGlvbnMiIFR5cGVOYW1lPSJvcGM6VUludDE2"
"IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZWZl"
"cmVuY2VzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVm"
"ZXJlbmNlcyIgVHlwZU5hbWU9InRuczpSZWZlcmVuY2VOb2RlIiBMZW5ndGhGaWVsZD0iTm9PZlJl"
"ZmVyZW5jZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJc0Fic3RyYWN0IiBUeXBlTmFtZT0i"
"b3BjOkJvb2xlYW4iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTeW1tZXRyaWMiIFR5cGVOYW1l"
"PSJvcGM6Qm9vbGVhbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkludmVyc2VOYW1lIiBUeXBl"
"TmFtZT0idWE6TG9jYWxpemVkVGV4dCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAg"
"PG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJNZXRob2ROb2RlIiBCYXNlVHlwZT0idG5zOkluc3Rh"
"bmNlTm9kZSI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2Rl"
"SWQiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUNs"
"YXNzIiBUeXBlTmFtZT0idG5zOk5vZGVDbGFzcyIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJCcm93c2VOYW1lIiBUeXBlTmFtZT0idWE6UXVhbGlmaWVkTmFt"
"ZSIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNwbGF5"
"TmFtZSIgVHlwZU5hbWU9InVhOkxvY2FsaXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVzY3JpcHRpb24iIFR5cGVOYW1lPSJ1YTpMb2NhbGl6"
"ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ildy"
"aXRlTWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0K";
    memcpy(xmlValue.data + 82685, buf_17, 4864);
    char *buf_18 = "ICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlcldyaXRlTWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJvbGVQ"
"ZXJtaXNzaW9ucyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9InRuczpSb2xlUGVybWlzc2lvblR5cGUiIExlbmd0"
"aEZpZWxkPSJOb09mUm9sZVBlcm1pc3Npb25zIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9P"
"ZlVzZXJSb2xlUGVybWlzc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJVc2VyUm9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0idG5zOlJvbGVQZXJtaXNz"
"aW9uVHlwZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZVc2VyUm9sZVBlcm1pc3Npb25zIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iQWNjZXNzUmVzdHJpY3Rpb25zIiBUeXBlTmFtZT0ib3BjOlVJbnQxNiIg"
"U291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUmVmZXJl"
"bmNlcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlZmVy"
"ZW5jZXMiIFR5cGVOYW1lPSJ0bnM6UmVmZXJlbmNlTm9kZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZWZl"
"cmVuY2VzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRXhlY3V0YWJsZSIgVHlwZU5hbWU9Im9w"
"YzpCb29sZWFuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlckV4ZWN1dGFibGUiIFR5cGVO"
"YW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpT"
"dHJ1Y3R1cmVkVHlwZSBOYW1lPSJWaWV3Tm9kZSIgQmFzZVR5cGU9InRuczpJbnN0YW5jZU5vZGUi"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUlkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiBTb3Vy"
"Y2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVDbGFzcyIgVHlw"
"ZU5hbWU9InRuczpOb2RlQ2xhc3MiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iQnJvd3NlTmFtZSIgVHlwZU5hbWU9InVhOlF1YWxpZmllZE5hbWUiIFNvdXJj"
"ZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5"
"cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIg"
"U291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZU1hc2si"
"IFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlVzZXJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VU"
"eXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSb2xlUGVybWlzc2lv"
"bnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSb2xlUGVy"
"bWlzc2lvbnMiIFR5cGVOYW1lPSJ0bnM6Um9sZVBlcm1pc3Npb25UeXBlIiBMZW5ndGhGaWVsZD0i"
"Tm9PZlJvbGVQZXJtaXNzaW9ucyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZVc2VyUm9s"
"ZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iVXNlclJvbGVQZXJtaXNzaW9ucyIgVHlwZU5hbWU9InRuczpSb2xlUGVybWlzc2lvblR5cGUi"
"IExlbmd0aEZpZWxkPSJOb09mVXNlclJvbGVQZXJtaXNzaW9ucyIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkFjY2Vzc1Jlc3RyaWN0aW9ucyIgVHlwZU5hbWU9Im9wYzpVSW50MTYiIFNvdXJjZVR5"
"cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlZmVyZW5jZXMiIFR5"
"cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VzIiBU"
"eXBlTmFtZT0idG5zOlJlZmVyZW5jZU5vZGUiIExlbmd0aEZpZWxkPSJOb09mUmVmZXJlbmNlcyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNvbnRhaW5zTm9Mb29wcyIgVHlwZU5hbWU9Im9wYzpC"
"b29sZWFuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRXZlbnROb3RpZmllciIgVHlwZU5hbWU9"
"Im9wYzpCeXRlIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVy"
"ZWRUeXBlIE5hbWU9IkRhdGFUeXBlTm9kZSIgQmFzZVR5cGU9InRuczpUeXBlTm9kZSI+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIFNvdXJjZVR5cGU9"
"InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUNsYXNzIiBUeXBlTmFtZT0i"
"dG5zOk5vZGVDbGFzcyIgU291cmNlVHlwZT0idG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJCcm93c2VOYW1lIiBUeXBlTmFtZT0idWE6UXVhbGlmaWVkTmFtZSIgU291cmNlVHlwZT0i"
"dG5zOk5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNwbGF5TmFtZSIgVHlwZU5hbWU9"
"InVhOkxvY2FsaXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iRGVzY3JpcHRpb24iIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VU"
"eXBlPSJ0bnM6Tm9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IldyaXRlTWFzayIgVHlwZU5h"
"bWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iVXNlcldyaXRlTWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRu"
"czpOb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJvbGVQZXJtaXNzaW9ucyIgVHlw"
"ZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJvbGVQZXJtaXNzaW9u"
"cyIgVHlwZU5hbWU9InRuczpSb2xlUGVybWlzc2lvblR5cGUiIExlbmd0aEZpZWxkPSJOb09mUm9s"
"ZVBlcm1pc3Npb25zIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlVzZXJSb2xlUGVybWlz"
"c2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2Vy"
"Um9sZVBlcm1pc3Npb25zIiBUeXBlTmFtZT0idG5zOlJvbGVQZXJtaXNzaW9uVHlwZSIgTGVuZ3Ro"
"RmllbGQ9Ik5vT2ZVc2VyUm9sZVBlcm1pc3Npb25zIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"QWNjZXNzUmVzdHJpY3Rpb25zIiBUeXBlTmFtZT0ib3BjOlVJbnQxNiIgU291cmNlVHlwZT0idG5z"
"Ok5vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUmVmZXJlbmNlcyIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlZmVyZW5jZXMiIFR5cGVOYW1l"
"PSJ0bnM6UmVmZXJlbmNlTm9kZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZWZlcmVuY2VzIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iSXNBYnN0cmFjdCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVR5cGVEZWZpbml0aW9uIiBUeXBlTmFtZT0idWE6RXh0";
    memcpy(xmlValue.data + 87549, buf_18, 4864);
    char *buf_19 = "ZW5zaW9uT2JqZWN0IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVj"
"dHVyZWRUeXBlIE5hbWU9IlJlZmVyZW5jZU5vZGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmpl"
"Y3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVmZXJlbmNlVHlwZUlkIiBUeXBlTmFtZT0idWE6"
"Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSXNJbnZlcnNlIiBUeXBlTmFtZT0ib3Bj"
"OkJvb2xlYW4iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUYXJnZXRJZCIgVHlwZU5hbWU9InVh"
"OkV4cGFuZGVkTm9kZUlkIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IkFyZ3VtZW50IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVR5cGUiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJWYWx1ZVJhbmsiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mQXJyYXlEaW1lbnNpb25zIiBUeXBlTmFtZT0ib3BjOklu"
"dDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQXJyYXlEaW1lbnNpb25zIiBUeXBlTmFtZT0i"
"b3BjOlVJbnQzMiIgTGVuZ3RoRmllbGQ9Ik5vT2ZBcnJheURpbWVuc2lvbnMiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5hbWU9InVhOkxvY2FsaXplZFRleHQiIC8+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i"
"RW51bVZhbHVlVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJWYWx1ZSIgVHlwZU5hbWU9Im9wYzpJbnQ2NCIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkRpc3BsYXlOYW1lIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIg"
"Lz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1l"
"PSJFbnVtRmllbGQiIEJhc2VUeXBlPSJ0bnM6RW51bVZhbHVlVHlwZSI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJWYWx1ZSIgVHlwZU5hbWU9Im9wYzpJbnQ2NCIgU291cmNlVHlwZT0idG5zOkVudW1W"
"YWx1ZVR5cGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNwbGF5TmFtZSIgVHlwZU5hbWU9"
"InVhOkxvY2FsaXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpFbnVtVmFsdWVUeXBlIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iRGVzY3JpcHRpb24iIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0"
"IiBTb3VyY2VUeXBlPSJ0bnM6RW51bVZhbHVlVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4N"
"Cg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik9wdGlvblNldCIgQmFzZVR5cGU9InVhOkV4"
"dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJWYWx1ZSIgVHlwZU5hbWU9Im9w"
"YzpCeXRlU3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVmFsaWRCaXRzIiBUeXBlTmFt"
"ZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iVW5pb24iIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3Qi"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFtZT0iTm9y"
"bWFsaXplZFN0cmluZyI+DQogIDwvb3BjOk9wYXF1ZVR5cGU+DQoNCiAgPG9wYzpPcGFxdWVUeXBl"
"IE5hbWU9IkRlY2ltYWxTdHJpbmciPg0KICA8L29wYzpPcGFxdWVUeXBlPg0KDQogIDxvcGM6T3Bh"
"cXVlVHlwZSBOYW1lPSJEdXJhdGlvblN0cmluZyI+DQogIDwvb3BjOk9wYXF1ZVR5cGU+DQoNCiAg"
"PG9wYzpPcGFxdWVUeXBlIE5hbWU9IlRpbWVTdHJpbmciPg0KICA8L29wYzpPcGFxdWVUeXBlPg0K"
"DQogIDxvcGM6T3BhcXVlVHlwZSBOYW1lPSJEYXRlU3RyaW5nIj4NCiAgPC9vcGM6T3BhcXVlVHlw"
"ZT4NCg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFtZT0iRHVyYXRpb24iPg0KICA8L29wYzpPcGFxdWVU"
"eXBlPg0KDQogIDxvcGM6T3BhcXVlVHlwZSBOYW1lPSJVdGNUaW1lIj4NCiAgPC9vcGM6T3BhcXVl"
"VHlwZT4NCg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFtZT0iTG9jYWxlSWQiPg0KICA8L29wYzpPcGFx"
"dWVUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVGltZVpvbmVEYXRhVHlwZSIg"
"QmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJPZmZz"
"ZXQiIFR5cGVOYW1lPSJvcGM6SW50MTYiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXlsaWdo"
"dFNhdmluZ0luT2Zmc2V0IiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6T3BhcXVlVHlwZSBOYW1lPSJJbmRleCI+DQogIDwvb3BjOk9w"
"YXF1ZVR5cGU+DQoNCiAgPG9wYzpPcGFxdWVUeXBlIE5hbWU9IkludGVnZXJJZCI+DQogIDwvb3Bj"
"Ok9wYXF1ZVR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVkVHlwZSBOYW1lPSJBcHBsaWNhdGlvblR5"
"cGUiIExlbmd0aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNl"
"cnZlciIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQ2xpZW50"
"IiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJDbGllbnRBbmRT"
"ZXJ2ZXIiIFZhbHVlPSIyIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkRpc2Nv"
"dmVyeVNlcnZlciIgVmFsdWU9IjMiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxv"
"cGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQXBwbGljYXRpb25EZXNjcmlwdGlvbiIgQmFzZVR5cGU9"
"InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBcHBsaWNhdGlvblVy"
"aSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQcm9kdWN0"
"VXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFwcGxp"
"Y2F0aW9uTmFtZSIgVHlwZU5hbWU9InVhOkxvY2FsaXplZFRleHQiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJBcHBsaWNhdGlvblR5cGUiIFR5cGVOYW1lPSJ0bnM6QXBwbGljYXRpb25UeXBlIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iR2F0ZXdheVNlcnZlclVyaSIgVHlwZU5hbWU9Im9wYzpT"
"dHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNjb3ZlcnlQcm9maWxlVXJpIiBUeXBl"
"TmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEaXNjb3ZlcnlV"
"cmxzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzY292"
"ZXJ5VXJscyIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mRGlzY292ZXJ5";
    memcpy(xmlValue.data + 92413, buf_19, 4864);
    char *buf_20 = "VXJscyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlw"
"ZSBOYW1lPSJSZXF1ZXN0SGVhZGVyIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkF1dGhlbnRpY2F0aW9uVG9rZW4iIFR5cGVOYW1lPSJ1YTpOb2Rl"
"SWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUaW1lc3RhbXAiIFR5cGVOYW1lPSJvcGM6RGF0"
"ZVRpbWUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1ZXN0SGFuZGxlIiBUeXBlTmFtZT0i"
"b3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJldHVybkRpYWdub3N0aWNzIiBU"
"eXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkF1ZGl0RW50cnlJ"
"ZCIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUaW1lb3V0"
"SGludCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBZGRp"
"dGlvbmFsSGVhZGVyIiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiAvPg0KICA8L29wYzpT"
"dHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlc3BvbnNlSGVh"
"ZGVyIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlRpbWVzdGFtcCIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlcXVlc3RIYW5kbGUiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iU2VydmljZVJlc3VsdCIgVHlwZU5hbWU9InVhOlN0YXR1c0NvZGUiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJTZXJ2aWNlRGlhZ25vc3RpY3MiIFR5cGVOYW1lPSJ1YTpEaWFnbm9z"
"dGljSW5mbyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTdHJpbmdUYWJsZSIgVHlwZU5h"
"bWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN0cmluZ1RhYmxlIiBUeXBl"
"TmFtZT0ib3BjOlN0cmluZyIgTGVuZ3RoRmllbGQ9Ik5vT2ZTdHJpbmdUYWJsZSIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkFkZGl0aW9uYWxIZWFkZXIiIFR5cGVOYW1lPSJ1YTpFeHRlbnNpb25P"
"YmplY3QiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6T3BhcXVlVHlwZSBO"
"YW1lPSJWZXJzaW9uVGltZSI+DQogIDwvb3BjOk9wYXF1ZVR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1"
"cmVkVHlwZSBOYW1lPSJTZXJ2aWNlRmF1bHQiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3Qi"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVz"
"cG9uc2VIZWFkZXIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0"
"dXJlZFR5cGUgTmFtZT0iU2Vzc2lvbmxlc3NJbnZva2VSZXF1ZXN0VHlwZSIgQmFzZVR5cGU9InVh"
"OkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVcmlzVmVyc2lvbiIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTmFtZXNwYWNl"
"VXJpcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWVz"
"cGFjZVVyaXMiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiBMZW5ndGhGaWVsZD0iTm9PZk5hbWVzcGFj"
"ZVVyaXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mU2VydmVyVXJpcyIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlclVyaXMiIFR5cGVOYW1l"
"PSJvcGM6U3RyaW5nIiBMZW5ndGhGaWVsZD0iTm9PZlNlcnZlclVyaXMiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJOb09mTG9jYWxlSWRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTG9jYWxlSWRzIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgTGVuZ3RoRmll"
"bGQ9Ik5vT2ZMb2NhbGVJZHMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2aWNlSWQiIFR5"
"cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3Bj"
"OlN0cnVjdHVyZWRUeXBlIE5hbWU9IlNlc3Npb25sZXNzSW52b2tlUmVzcG9uc2VUeXBlIiBCYXNl"
"VHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOYW1l"
"c3BhY2VVcmlzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"TmFtZXNwYWNlVXJpcyIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mTmFt"
"ZXNwYWNlVXJpcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTZXJ2ZXJVcmlzIiBUeXBl"
"TmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2VydmVyVXJpcyIgVHlw"
"ZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mU2VydmVyVXJpcyIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IlNlcnZpY2VJZCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogIDwv"
"b3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRmluZFNl"
"cnZlcnNSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuZHBvaW50VXJsIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZMb2NhbGVJZHMiIFR5cGVOYW1lPSJvcGM6SW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJMb2NhbGVJZHMiIFR5cGVOYW1lPSJvcGM6U3Ry"
"aW5nIiBMZW5ndGhGaWVsZD0iTm9PZkxvY2FsZUlkcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5vT2ZTZXJ2ZXJVcmlzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iU2VydmVyVXJpcyIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09m"
"U2VydmVyVXJpcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1"
"cmVkVHlwZSBOYW1lPSJGaW5kU2VydmVyc1Jlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9u"
"T2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0i"
"dG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlNlcnZlcnMi"
"IFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2ZXJzIiBU"
"eXBlTmFtZT0idG5zOkFwcGxpY2F0aW9uRGVzY3JpcHRpb24iIExlbmd0aEZpZWxkPSJOb09mU2Vy"
"dmVycyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlw"
"ZSBOYW1lPSJTZXJ2ZXJPbk5ldHdvcmsiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iUmVjb3JkSWQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iU2VydmVyTmFtZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+";
    memcpy(xmlValue.data + 97277, buf_20, 4864);
    char *buf_21 = "DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNjb3ZlcnlVcmwiIFR5cGVOYW1lPSJvcGM6U3RyaW5n"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlNlcnZlckNhcGFiaWxpdGllcyIgVHlwZU5h"
"bWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlckNhcGFiaWxpdGll"
"cyIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mU2VydmVyQ2FwYWJpbGl0"
"aWVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9IkZpbmRTZXJ2ZXJzT25OZXR3b3JrUmVxdWVzdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lv"
"bk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1ZXN0SGVhZGVyIiBUeXBlTmFtZT0i"
"dG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdGFydGluZ1JlY29y"
"ZElkIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1heFJl"
"Y29yZHNUb1JldHVybiIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJOb09mU2VydmVyQ2FwYWJpbGl0eUZpbHRlciIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlckNhcGFiaWxpdHlGaWx0ZXIiIFR5cGVOYW1lPSJv"
"cGM6U3RyaW5nIiBMZW5ndGhGaWVsZD0iTm9PZlNlcnZlckNhcGFiaWxpdHlGaWx0ZXIiIC8+DQog"
"IDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRmlu"
"ZFNlcnZlcnNPbk5ldHdvcmtSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRuczpSZXNw"
"b25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ikxhc3RDb3VudGVyUmVzZXRUaW1l"
"IiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlNl"
"cnZlcnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2"
"ZXJzIiBUeXBlTmFtZT0idG5zOlNlcnZlck9uTmV0d29yayIgTGVuZ3RoRmllbGQ9Ik5vT2ZTZXJ2"
"ZXJzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFt"
"ZT0iQXBwbGljYXRpb25JbnN0YW5jZUNlcnRpZmljYXRlIj4NCiAgPC9vcGM6T3BhcXVlVHlwZT4N"
"Cg0KICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9Ik1lc3NhZ2VTZWN1cml0eU1vZGUiIExlbmd0"
"aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkludmFsaWQiIFZh"
"bHVlPSIwIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik5vbmUiIFZhbHVlPSIx"
"IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNpZ24iIFZhbHVlPSIyIiAvPg0K"
"ICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNpZ25BbmRFbmNyeXB0IiBWYWx1ZT0iMyIg"
"Lz4NCiAgPC9vcGM6RW51bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVkVHlwZSBOYW1l"
"PSJVc2VyVG9rZW5UeXBlIiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRW"
"YWx1ZSBOYW1lPSJBbm9ueW1vdXMiIFZhbHVlPSIwIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZh"
"bHVlIE5hbWU9IlVzZXJOYW1lIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1"
"ZSBOYW1lPSJDZXJ0aWZpY2F0ZSIgVmFsdWU9IjIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFs"
"dWUgTmFtZT0iSXNzdWVkVG9rZW4iIFZhbHVlPSIzIiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlw"
"ZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlVzZXJUb2tlblBvbGljeSIgQmFzZVR5"
"cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQb2xpY3lJZCIg"
"VHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUb2tlblR5cGUi"
"IFR5cGVOYW1lPSJ0bnM6VXNlclRva2VuVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Iklz"
"c3VlZFRva2VuVHlwZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJJc3N1ZXJFbmRwb2ludFVybCIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJTZWN1cml0eVBvbGljeVVyaSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i"
"RW5kcG9pbnREZXNjcmlwdGlvbiIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJFbmRwb2ludFVybCIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2ZXIiIFR5cGVOYW1lPSJ0bnM6QXBwbGljYXRpb25EZXNj"
"cmlwdGlvbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlckNlcnRpZmljYXRlIiBUeXBl"
"TmFtZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eU1v"
"ZGUiIFR5cGVOYW1lPSJ0bnM6TWVzc2FnZVNlY3VyaXR5TW9kZSIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlNlY3VyaXR5UG9saWN5VXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9Ik5vT2ZVc2VySWRlbnRpdHlUb2tlbnMiIFR5cGVOYW1lPSJvcGM6SW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VySWRlbnRpdHlUb2tlbnMiIFR5cGVOYW1l"
"PSJ0bnM6VXNlclRva2VuUG9saWN5IiBMZW5ndGhGaWVsZD0iTm9PZlVzZXJJZGVudGl0eVRva2Vu"
"cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRyYW5zcG9ydFByb2ZpbGVVcmkiIFR5cGVOYW1l"
"PSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2VjdXJpdHlMZXZlbCIgVHlw"
"ZU5hbWU9Im9wYzpCeXRlIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IkdldEVuZHBvaW50c1JlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRl"
"bnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5h"
"bWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRW5kcG9pbnRV"
"cmwiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkxv"
"Y2FsZUlkcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ikxv"
"Y2FsZUlkcyIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mTG9jYWxlSWRz"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlByb2ZpbGVVcmlzIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUHJvZmlsZVVyaXMiIFR5cGVOYW1lPSJv"
"cGM6U3RyaW5nIiBMZW5ndGhGaWVsZD0iTm9PZlByb2ZpbGVVcmlzIiAvPg0KICA8L29wYzpTdHJ1"
"Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkdldEVuZHBvaW50c1Jl";
    memcpy(xmlValue.data + 102141, buf_21, 4864);
    char *buf_22 = "c3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iTm9PZkVuZHBvaW50cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuZHBvaW50cyIgVHlwZU5hbWU9InRuczpFbmRwb2ludERl"
"c2NyaXB0aW9uIiBMZW5ndGhGaWVsZD0iTm9PZkVuZHBvaW50cyIgLz4NCiAgPC9vcGM6U3RydWN0"
"dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJSZWdpc3RlcmVkU2VydmVy"
"IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNl"
"cnZlclVyaSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQ"
"cm9kdWN0VXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5vT2ZTZXJ2ZXJOYW1lcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlNlcnZlck5hbWVzIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgTGVuZ3RoRmll"
"bGQ9Ik5vT2ZTZXJ2ZXJOYW1lcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlclR5cGUi"
"IFR5cGVOYW1lPSJ0bnM6QXBwbGljYXRpb25UeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"R2F0ZXdheVNlcnZlclVyaSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOb09mRGlzY292ZXJ5VXJscyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkRpc2NvdmVyeVVybHMiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiBMZW5n"
"dGhGaWVsZD0iTm9PZkRpc2NvdmVyeVVybHMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZW1h"
"cGhvcmVGaWxlUGF0aCIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJJc09ubGluZSIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1"
"cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlZ2lzdGVyU2VydmVyUmVx"
"dWVzdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJSZXF1ZXN0SGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJTZXJ2ZXIiIFR5cGVOYW1lPSJ0bnM6UmVnaXN0ZXJlZFNlcnZlciIgLz4N"
"CiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJS"
"ZWdpc3RlclNlcnZlclJlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNl"
"SGVhZGVyIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRU"
"eXBlIE5hbWU9IkRpc2NvdmVyeUNvbmZpZ3VyYXRpb24iIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25P"
"YmplY3QiPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9Ik1kbnNEaXNjb3ZlcnlDb25maWd1cmF0aW9uIiBCYXNlVHlwZT0idG5zOkRpc2NvdmVy"
"eUNvbmZpZ3VyYXRpb24iPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWRuc1NlcnZlck5hbWUiIFR5"
"cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlNlcnZlckNh"
"cGFiaWxpdGllcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlNlcnZlckNhcGFiaWxpdGllcyIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIExlbmd0aEZpZWxkPSJO"
"b09mU2VydmVyQ2FwYWJpbGl0aWVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlZ2lzdGVyU2VydmVyMlJlcXVlc3QiIEJhc2VUeXBl"
"PSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRl"
"ciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"U2VydmVyIiBUeXBlTmFtZT0idG5zOlJlZ2lzdGVyZWRTZXJ2ZXIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOb09mRGlzY292ZXJ5Q29uZmlndXJhdGlvbiIgVHlwZU5hbWU9Im9wYzpJbnQzMiIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpc2NvdmVyeUNvbmZpZ3VyYXRpb24iIFR5cGVOYW1l"
"PSJ1YTpFeHRlbnNpb25PYmplY3QiIExlbmd0aEZpZWxkPSJOb09mRGlzY292ZXJ5Q29uZmlndXJh"
"dGlvbiIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlw"
"ZSBOYW1lPSJSZWdpc3RlclNlcnZlcjJSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9i"
"amVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRu"
"czpSZXNwb25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZDb25maWd1cmF0"
"aW9uUmVzdWx0cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IkNvbmZpZ3VyYXRpb25SZXN1bHRzIiBUeXBlTmFtZT0idWE6U3RhdHVzQ29kZSIgTGVuZ3RoRmll"
"bGQ9Ik5vT2ZDb25maWd1cmF0aW9uUmVzdWx0cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5v"
"T2ZEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIgTGVu"
"Z3RoRmllbGQ9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBl"
"Pg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iU2VjdXJpdHlUb2tlblJlcXVlc3RUeXBl"
"IiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJJc3N1"
"ZSIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUmVuZXciIFZh"
"bHVlPSIxIiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRU"
"eXBlIE5hbWU9IkNoYW5uZWxTZWN1cml0eVRva2VuIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2Jq"
"ZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNoYW5uZWxJZCIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUb2tlbklkIiBUeXBlTmFtZT0ib3BjOlVJbnQz"
"MiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNyZWF0ZWRBdCIgVHlwZU5hbWU9Im9wYzpEYXRl"
"VGltZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJldmlzZWRMaWZldGltZSIgVHlwZU5hbWU9"
"Im9wYzpVSW50MzIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0"
"dXJlZFR5cGUgTmFtZT0iT3BlblNlY3VyZUNoYW5uZWxSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0"
"ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVO";
    memcpy(xmlValue.data + 107005, buf_22, 4864);
    char *buf_23 = "YW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNsaWVudFBy"
"b3RvY29sVmVyc2lvbiIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJSZXF1ZXN0VHlwZSIgVHlwZU5hbWU9InRuczpTZWN1cml0eVRva2VuUmVxdWVzdFR5cGUi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eU1vZGUiIFR5cGVOYW1lPSJ0bnM6TWVz"
"c2FnZVNlY3VyaXR5TW9kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNsaWVudE5vbmNlIiBU"
"eXBlTmFtZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1ZXN0"
"ZWRMaWZldGltZSIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRU"
"eXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iT3BlblNlY3VyZUNoYW5uZWxSZXNw"
"b25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRuczpSZXNwb25zZUhlYWRlciIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IlNlcnZlclByb3RvY29sVmVyc2lvbiIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eVRva2VuIiBUeXBlTmFtZT0idG5z"
"OkNoYW5uZWxTZWN1cml0eVRva2VuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2VydmVyTm9u"
"Y2UiIFR5cGVOYW1lPSJvcGM6Qnl0ZVN0cmluZyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+"
"DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJDbG9zZVNlY3VyZUNoYW5uZWxSZXF1ZXN0"
"IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJl"
"cXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAgPC9vcGM6U3Ry"
"dWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJDbG9zZVNlY3VyZUNo"
"YW5uZWxSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRuczpSZXNwb25zZUhlYWRlciIg"
"Lz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1l"
"PSJTaWduZWRTb2Z0d2FyZUNlcnRpZmljYXRlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNlcnRpZmljYXRlRGF0YSIgVHlwZU5hbWU9Im9wYzpC"
"eXRlU3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2lnbmF0dXJlIiBUeXBlTmFtZT0i"
"b3BjOkJ5dGVTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6T3Bh"
"cXVlVHlwZSBOYW1lPSJTZXNzaW9uQXV0aGVudGljYXRpb25Ub2tlbiI+DQogIDwvb3BjOk9wYXF1"
"ZVR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTaWduYXR1cmVEYXRhIiBCYXNl"
"VHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFsZ29yaXRo"
"bSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTaWduYXR1"
"cmUiIFR5cGVOYW1lPSJvcGM6Qnl0ZVN0cmluZyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+"
"DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJDcmVhdGVTZXNzaW9uUmVxdWVzdCIgQmFz"
"ZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1ZXN0"
"SGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJDbGllbnREZXNjcmlwdGlvbiIgVHlwZU5hbWU9InRuczpBcHBsaWNhdGlvbkRlc2NyaXB0"
"aW9uIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2VydmVyVXJpIiBUeXBlTmFtZT0ib3BjOlN0"
"cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuZHBvaW50VXJsIiBUeXBlTmFtZT0ib3Bj"
"OlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlc3Npb25OYW1lIiBUeXBlTmFtZT0i"
"b3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNsaWVudE5vbmNlIiBUeXBlTmFt"
"ZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDbGllbnRDZXJ0aWZp"
"Y2F0ZSIgVHlwZU5hbWU9Im9wYzpCeXRlU3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"UmVxdWVzdGVkU2Vzc2lvblRpbWVvdXQiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTWF4UmVzcG9uc2VNZXNzYWdlU2l6ZSIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUg"
"TmFtZT0iQ3JlYXRlU2Vzc2lvblJlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJl"
"c3BvbnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vzc2lvbklkIiBUeXBlTmFt"
"ZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQXV0aGVudGljYXRpb25Ub2tl"
"biIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJldmlzZWRT"
"ZXNzaW9uVGltZW91dCIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJTZXJ2ZXJOb25jZSIgVHlwZU5hbWU9Im9wYzpCeXRlU3RyaW5nIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iU2VydmVyQ2VydGlmaWNhdGUiIFR5cGVOYW1lPSJvcGM6Qnl0ZVN0cmluZyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTZXJ2ZXJFbmRwb2ludHMiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2ZXJFbmRwb2ludHMiIFR5cGVO"
"YW1lPSJ0bnM6RW5kcG9pbnREZXNjcmlwdGlvbiIgTGVuZ3RoRmllbGQ9Ik5vT2ZTZXJ2ZXJFbmRw"
"b2ludHMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mU2VydmVyU29mdHdhcmVDZXJ0aWZp"
"Y2F0ZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2"
"ZXJTb2Z0d2FyZUNlcnRpZmljYXRlcyIgVHlwZU5hbWU9InRuczpTaWduZWRTb2Z0d2FyZUNlcnRp"
"ZmljYXRlIiBMZW5ndGhGaWVsZD0iTm9PZlNlcnZlclNvZnR3YXJlQ2VydGlmaWNhdGVzIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iU2VydmVyU2lnbmF0dXJlIiBUeXBlTmFtZT0idG5zOlNpZ25h"
"dHVyZURhdGEiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNYXhSZXF1ZXN0TWVzc2FnZVNpemUi"
"IFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlVzZXJJZGVudGl0eVRva2VuIiBCYXNlVHlwZT0idWE6"
"RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlBvbGljeUlkIiBUeXBlTmFt"
"ZT0ib3BjOlN0cmluZyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1";
    memcpy(xmlValue.data + 111869, buf_23, 4864);
    char *buf_24 = "Y3R1cmVkVHlwZSBOYW1lPSJBbm9ueW1vdXNJZGVudGl0eVRva2VuIiBCYXNlVHlwZT0idG5zOlVz"
"ZXJJZGVudGl0eVRva2VuIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlBvbGljeUlkIiBUeXBlTmFt"
"ZT0ib3BjOlN0cmluZyIgU291cmNlVHlwZT0idG5zOlVzZXJJZGVudGl0eVRva2VuIiAvPg0KICA8"
"L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlVzZXJO"
"YW1lSWRlbnRpdHlUb2tlbiIgQmFzZVR5cGU9InRuczpVc2VySWRlbnRpdHlUb2tlbiI+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJQb2xpY3lJZCIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIFNvdXJjZVR5"
"cGU9InRuczpVc2VySWRlbnRpdHlUb2tlbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZXJO"
"YW1lIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlBhc3N3"
"b3JkIiBUeXBlTmFtZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJF"
"bmNyeXB0aW9uQWxnb3JpdGhtIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgPC9vcGM6U3Ry"
"dWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJYNTA5SWRlbnRpdHlU"
"b2tlbiIgQmFzZVR5cGU9InRuczpVc2VySWRlbnRpdHlUb2tlbiI+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJQb2xpY3lJZCIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIFNvdXJjZVR5cGU9InRuczpVc2Vy"
"SWRlbnRpdHlUb2tlbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNlcnRpZmljYXRlRGF0YSIg"
"VHlwZU5hbWU9Im9wYzpCeXRlU3RyaW5nIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0K"
"ICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Iklzc3VlZElkZW50aXR5VG9rZW4iIEJhc2VUeXBl"
"PSJ0bnM6VXNlcklkZW50aXR5VG9rZW4iPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUG9saWN5SWQi"
"IFR5cGVOYW1lPSJvcGM6U3RyaW5nIiBTb3VyY2VUeXBlPSJ0bnM6VXNlcklkZW50aXR5VG9rZW4i"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUb2tlbkRhdGEiIFR5cGVOYW1lPSJvcGM6Qnl0ZVN0"
"cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuY3J5cHRpb25BbGdvcml0aG0iIFR5cGVO"
"YW1lPSJvcGM6U3RyaW5nIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOk9w"
"YXF1ZVR5cGUgTmFtZT0iUnNhRW5jcnlwdGVkU2VjcmV0Ij4NCiAgPC9vcGM6T3BhcXVlVHlwZT4N"
"Cg0KICA8b3BjOk9wYXF1ZVR5cGUgTmFtZT0iRWNjRW5jcnlwdGVkU2VjcmV0Ij4NCiAgPC9vcGM6"
"T3BhcXVlVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkFjdGl2YXRlU2Vzc2lv"
"blJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iQ2xpZW50U2lnbmF0dXJlIiBUeXBlTmFtZT0idG5zOlNpZ25hdHVy"
"ZURhdGEiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mQ2xpZW50U29mdHdhcmVDZXJ0aWZp"
"Y2F0ZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDbGll"
"bnRTb2Z0d2FyZUNlcnRpZmljYXRlcyIgVHlwZU5hbWU9InRuczpTaWduZWRTb2Z0d2FyZUNlcnRp"
"ZmljYXRlIiBMZW5ndGhGaWVsZD0iTm9PZkNsaWVudFNvZnR3YXJlQ2VydGlmaWNhdGVzIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkxvY2FsZUlkcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkxvY2FsZUlkcyIgVHlwZU5hbWU9Im9wYzpTdHJpbmci"
"IExlbmd0aEZpZWxkPSJOb09mTG9jYWxlSWRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNl"
"cklkZW50aXR5VG9rZW4iIFR5cGVOYW1lPSJ1YTpFeHRlbnNpb25PYmplY3QiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJVc2VyVG9rZW5TaWduYXR1cmUiIFR5cGVOYW1lPSJ0bnM6U2lnbmF0dXJl"
"RGF0YSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlw"
"ZSBOYW1lPSJBY3RpdmF0ZVNlc3Npb25SZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9i"
"amVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRu"
"czpSZXNwb25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlck5vbmNlIiBU"
"eXBlTmFtZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUmVz"
"dWx0cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3Vs"
"dHMiIFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVsZD0iTm9PZlJlc3VsdHMiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFt"
"ZT0idWE6RGlhZ25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9zIiAv"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9"
"IkNsb3NlU2Vzc2lvblJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVh"
"ZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVsZXRlU3Vic2NyaXB0aW9ucyIgVHlwZU5h"
"bWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IkNsb3NlU2Vzc2lvblJlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0"
"ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBl"
"TmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0K"
"ICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkNhbmNlbFJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpF"
"eHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlw"
"ZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVz"
"dEhhbmRsZSIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBl"
"Pg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQ2FuY2VsUmVzcG9uc2UiIEJhc2VUeXBl"
"PSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzcG9uc2VIZWFk"
"ZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJDYW5jZWxDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogIDwvb3BjOlN0cnVjdHVy"
"ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iTm9kZUF0dHJpYnV0ZXNNYXNr"
"IiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJOb25l";
    memcpy(xmlValue.data + 116733, buf_24, 4864);
    char *buf_25 = "IiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJBY2Nlc3NMZXZl"
"bCIgVmFsdWU9IjEiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQXJyYXlEaW1l"
"bnNpb25zIiBWYWx1ZT0iMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJCcm93"
"c2VOYW1lIiBWYWx1ZT0iNCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJDb250"
"YWluc05vTG9vcHMiIFZhbHVlPSI4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9"
"IkRhdGFUeXBlIiBWYWx1ZT0iMTYiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0i"
"RGVzY3JpcHRpb24iIFZhbHVlPSIzMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1l"
"PSJEaXNwbGF5TmFtZSIgVmFsdWU9IjY0IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5h"
"bWU9IkV2ZW50Tm90aWZpZXIiIFZhbHVlPSIxMjgiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFs"
"dWUgTmFtZT0iRXhlY3V0YWJsZSIgVmFsdWU9IjI1NiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRW"
"YWx1ZSBOYW1lPSJIaXN0b3JpemluZyIgVmFsdWU9IjUxMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0"
"ZWRWYWx1ZSBOYW1lPSJJbnZlcnNlTmFtZSIgVmFsdWU9IjEwMjQiIC8+DQogICAgPG9wYzpFbnVt"
"ZXJhdGVkVmFsdWUgTmFtZT0iSXNBYnN0cmFjdCIgVmFsdWU9IjIwNDgiIC8+DQogICAgPG9wYzpF"
"bnVtZXJhdGVkVmFsdWUgTmFtZT0iTWluaW11bVNhbXBsaW5nSW50ZXJ2YWwiIFZhbHVlPSI0MDk2"
"IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik5vZGVDbGFzcyIgVmFsdWU9Ijgx"
"OTIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm9kZUlkIiBWYWx1ZT0iMTYz"
"ODQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU3ltbWV0cmljIiBWYWx1ZT0i"
"MzI3NjgiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVXNlckFjY2Vzc0xldmVs"
"IiBWYWx1ZT0iNjU1MzYiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVXNlckV4"
"ZWN1dGFibGUiIFZhbHVlPSIxMzEwNzIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFt"
"ZT0iVXNlcldyaXRlTWFzayIgVmFsdWU9IjI2MjE0NCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRW"
"YWx1ZSBOYW1lPSJWYWx1ZVJhbmsiIFZhbHVlPSI1MjQyODgiIC8+DQogICAgPG9wYzpFbnVtZXJh"
"dGVkVmFsdWUgTmFtZT0iV3JpdGVNYXNrIiBWYWx1ZT0iMTA0ODU3NiIgLz4NCiAgICA8b3BjOkVu"
"dW1lcmF0ZWRWYWx1ZSBOYW1lPSJWYWx1ZSIgVmFsdWU9IjIwOTcxNTIiIC8+DQogICAgPG9wYzpF"
"bnVtZXJhdGVkVmFsdWUgTmFtZT0iRGF0YVR5cGVEZWZpbml0aW9uIiBWYWx1ZT0iNDE5NDMwNCIg"
"Lz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJSb2xlUGVybWlzc2lvbnMiIFZhbHVl"
"PSI4Mzg4NjA4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkFjY2Vzc1Jlc3Ry"
"aWN0aW9ucyIgVmFsdWU9IjE2Nzc3MjE2IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5h"
"bWU9IkFsbCIgVmFsdWU9IjMzNTU0NDMxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5h"
"bWU9IkJhc2VOb2RlIiBWYWx1ZT0iMjY1MDEyMjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFs"
"dWUgTmFtZT0iT2JqZWN0IiBWYWx1ZT0iMjY1MDEzNDgiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVk"
"VmFsdWUgTmFtZT0iT2JqZWN0VHlwZSIgVmFsdWU9IjI2NTAzMjY4IiAvPg0KICAgIDxvcGM6RW51"
"bWVyYXRlZFZhbHVlIE5hbWU9IlZhcmlhYmxlIiBWYWx1ZT0iMjY1NzEzODMiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVmFyaWFibGVUeXBlIiBWYWx1ZT0iMjg2MDA0MzgiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTWV0aG9kIiBWYWx1ZT0iMjY2MzI1NDgi"
"IC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUmVmZXJlbmNlVHlwZSIgVmFsdWU9"
"IjI2NTM3MDYwIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlZpZXciIFZhbHVl"
"PSIyNjUwMTM1NiIgLz4NCiAgPC9vcGM6RW51bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1"
"cmVkVHlwZSBOYW1lPSJOb2RlQXR0cmlidXRlcyIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVj"
"dCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTcGVjaWZpZWRBdHRyaWJ1dGVzIiBUeXBlTmFtZT0i"
"b3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpc3BsYXlOYW1lIiBUeXBlTmFt"
"ZT0idWE6TG9jYWxpemVkVGV4dCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0aW9u"
"IiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ildy"
"aXRlTWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJV"
"c2VyV3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgPC9vcGM6U3RydWN0dXJl"
"ZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJPYmplY3RBdHRyaWJ1dGVzIiBC"
"YXNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNwZWNp"
"ZmllZEF0dHJpYnV0ZXMiIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9k"
"ZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNwbGF5TmFtZSIgVHlwZU5h"
"bWU9InVhOkxvY2FsaXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBlTmFtZT0idWE6TG9jYWxpemVk"
"VGV4dCIgU291cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iV3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5v"
"ZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlcldyaXRlTWFzayIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkV2ZW50Tm90aWZpZXIiIFR5cGVOYW1lPSJvcGM6Qnl0ZSIgLz4N"
"CiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJW"
"YXJpYWJsZUF0dHJpYnV0ZXMiIEJhc2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iU3BlY2lmaWVkQXR0cmlidXRlcyIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IkRpc3BsYXlOYW1lIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5z"
"Ok5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVzY3JpcHRpb24iIFR5"
"cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMy";
    memcpy(xmlValue.data + 121597, buf_25, 4864);
    char *buf_26 = "IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJVc2VyV3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5v"
"ZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVmFsdWUiIFR5cGVOYW1lPSJ1"
"YTpWYXJpYW50IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YVR5cGUiIFR5cGVOYW1lPSJ1"
"YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJWYWx1ZVJhbmsiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mQXJyYXlEaW1lbnNpb25zIiBU"
"eXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQXJyYXlEaW1lbnNp"
"b25zIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgTGVuZ3RoRmllbGQ9Ik5vT2ZBcnJheURpbWVuc2lv"
"bnMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBY2Nlc3NMZXZlbCIgVHlwZU5hbWU9Im9wYzpC"
"eXRlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlckFjY2Vzc0xldmVsIiBUeXBlTmFtZT0i"
"b3BjOkJ5dGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNaW5pbXVtU2FtcGxpbmdJbnRlcnZh"
"bCIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJIaXN0b3Jp"
"emluZyIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4N"
"Cg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik1ldGhvZEF0dHJpYnV0ZXMiIEJhc2VUeXBl"
"PSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3BlY2lmaWVkQXR0"
"cmlidXRlcyIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmli"
"dXRlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpc3BsYXlOYW1lIiBUeXBlTmFtZT0idWE6"
"TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iRGVzY3JpcHRpb24iIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBT"
"b3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJX"
"cml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJp"
"YnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VyV3JpdGVNYXNrIiBUeXBlTmFtZT0i"
"b3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iRXhlY3V0YWJsZSIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iVXNlckV4ZWN1dGFibGUiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4N"
"CiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJP"
"YmplY3RUeXBlQXR0cmlidXRlcyIgQmFzZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyI+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJTcGVjaWZpZWRBdHRyaWJ1dGVzIiBUeXBlTmFtZT0ib3BjOlVJbnQz"
"MiIgU291cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0"
"bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIg"
"VHlwZU5hbWU9InVhOkxvY2FsaXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRl"
"cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IldyaXRlTWFzayIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlVzZXJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6"
"Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJc0Fic3RyYWN0IiBUeXBl"
"TmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iVmFyaWFibGVUeXBlQXR0cmlidXRlcyIgQmFzZVR5cGU9InRu"
"czpOb2RlQXR0cmlidXRlcyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTcGVjaWZpZWRBdHRyaWJ1"
"dGVzIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVz"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1lPSJ1YTpMb2Nh"
"bGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5hbWU9InVhOkxvY2FsaXplZFRleHQiIFNvdXJj"
"ZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IldyaXRl"
"TWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRl"
"cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZXJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6"
"VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJWYWx1ZSIgVHlwZU5hbWU9InVhOlZhcmlhbnQiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJEYXRhVHlwZSIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlZhbHVlUmFuayIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9Ik5vT2ZBcnJheURpbWVuc2lvbnMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJBcnJheURpbWVuc2lvbnMiIFR5cGVOYW1lPSJvcGM6VUludDMyIiBMZW5n"
"dGhGaWVsZD0iTm9PZkFycmF5RGltZW5zaW9ucyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Iklz"
"QWJzdHJhY3QiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5"
"cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJSZWZlcmVuY2VUeXBlQXR0cmlidXRl"
"cyIgQmFzZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJT"
"cGVjaWZpZWRBdHRyaWJ1dGVzIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5z"
"Ok5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5"
"cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5hbWU9InVhOkxvY2Fs"
"aXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IldyaXRlTWFzayIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRu"
"czpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZXJXcml0ZU1hc2si"
"IFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+";
    memcpy(xmlValue.data + 126461, buf_26, 4864);
    char *buf_27 = "DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJc0Fic3RyYWN0IiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4i"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTeW1tZXRyaWMiIFR5cGVOYW1lPSJvcGM6Qm9vbGVh"
"biIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkludmVyc2VOYW1lIiBUeXBlTmFtZT0idWE6TG9j"
"YWxpemVkVGV4dCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1"
"cmVkVHlwZSBOYW1lPSJEYXRhVHlwZUF0dHJpYnV0ZXMiIEJhc2VUeXBlPSJ0bnM6Tm9kZUF0dHJp"
"YnV0ZXMiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3BlY2lmaWVkQXR0cmlidXRlcyIgVHlwZU5h"
"bWU9Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkRpc3BsYXlOYW1lIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIg"
"U291cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"RGVzY3JpcHRpb24iIFR5cGVOYW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6"
"Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZU1hc2siIFR5cGVO"
"YW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJVc2VyV3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291"
"cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSXNB"
"YnN0cmFjdCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlw"
"ZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlZpZXdBdHRyaWJ1dGVzIiBCYXNlVHlw"
"ZT0idG5zOk5vZGVBdHRyaWJ1dGVzIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNwZWNpZmllZEF0"
"dHJpYnV0ZXMiIFR5cGVOYW1lPSJvcGM6VUludDMyIiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJp"
"YnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNwbGF5TmFtZSIgVHlwZU5hbWU9InVh"
"OkxvY2FsaXplZFRleHQiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIg"
"U291cmNlVHlwZT0idG5zOk5vZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"V3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5vZGVBdHRy"
"aWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNlcldyaXRlTWFzayIgVHlwZU5hbWU9"
"Im9wYzpVSW50MzIiIFNvdXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IkNvbnRhaW5zTm9Mb29wcyIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iRXZlbnROb3RpZmllciIgVHlwZU5hbWU9Im9wYzpCeXRlIiAv"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9"
"IkdlbmVyaWNBdHRyaWJ1dGVWYWx1ZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJBdHRyaWJ1dGVJZCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJWYWx1ZSIgVHlwZU5hbWU9InVhOlZhcmlhbnQiIC8+DQog"
"IDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iR2Vu"
"ZXJpY0F0dHJpYnV0ZXMiIEJhc2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iU3BlY2lmaWVkQXR0cmlidXRlcyIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIFNv"
"dXJjZVR5cGU9InRuczpOb2RlQXR0cmlidXRlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRp"
"c3BsYXlOYW1lIiBUeXBlTmFtZT0idWE6TG9jYWxpemVkVGV4dCIgU291cmNlVHlwZT0idG5zOk5v"
"ZGVBdHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVzY3JpcHRpb24iIFR5cGVO"
"YW1lPSJ1YTpMb2NhbGl6ZWRUZXh0IiBTb3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJXcml0ZU1hc2siIFR5cGVOYW1lPSJvcGM6VUludDMyIiBT"
"b3VyY2VUeXBlPSJ0bnM6Tm9kZUF0dHJpYnV0ZXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJV"
"c2VyV3JpdGVNYXNrIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgU291cmNlVHlwZT0idG5zOk5vZGVB"
"dHRyaWJ1dGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkF0dHJpYnV0ZVZhbHVlcyIg"
"VHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkF0dHJpYnV0ZVZh"
"bHVlcyIgVHlwZU5hbWU9InRuczpHZW5lcmljQXR0cmlidXRlVmFsdWUiIExlbmd0aEZpZWxkPSJO"
"b09mQXR0cmlidXRlVmFsdWVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3Bj"
"OlN0cnVjdHVyZWRUeXBlIE5hbWU9IkFkZE5vZGVzSXRlbSIgQmFzZVR5cGU9InVhOkV4dGVuc2lv"
"bk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQYXJlbnROb2RlSWQiIFR5cGVOYW1lPSJ1"
"YTpFeHBhbmRlZE5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlZmVyZW5jZVR5cGVJ"
"ZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3Rl"
"ZE5ld05vZGVJZCIgVHlwZU5hbWU9InVhOkV4cGFuZGVkTm9kZUlkIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iQnJvd3NlTmFtZSIgVHlwZU5hbWU9InVhOlF1YWxpZmllZE5hbWUiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJOb2RlQ2xhc3MiIFR5cGVOYW1lPSJ0bnM6Tm9kZUNsYXNzIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUF0dHJpYnV0ZXMiIFR5cGVOYW1lPSJ1YTpFeHRlbnNp"
"b25PYmplY3QiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUeXBlRGVmaW5pdGlvbiIgVHlwZU5h"
"bWU9InVhOkV4cGFuZGVkTm9kZUlkIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkFkZE5vZGVzUmVzdWx0IiBCYXNlVHlwZT0idWE6RXh0"
"ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN0YXR1c0NvZGUiIFR5cGVOYW1l"
"PSJ1YTpTdGF0dXNDb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWRkZWROb2RlSWQiIFR5"
"cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iQWRkTm9kZXNSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5z"
"aW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1l"
"PSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOb2Rlc1Rv"
"QWRkIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZXNU"
"b0FkZCIgVHlwZU5hbWU9InRuczpBZGROb2Rlc0l0ZW0iIExlbmd0aEZpZWxkPSJOb09mTm9kZXNU";
    memcpy(xmlValue.data + 131325, buf_27, 4864);
    char *buf_28 = "b0FkZCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlw"
"ZSBOYW1lPSJBZGROb2Rlc1Jlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3Bv"
"bnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3VsdHMiIFR5cGVOYW1l"
"PSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRzIiBUeXBlTmFtZT0i"
"dG5zOkFkZE5vZGVzUmVzdWx0IiBMZW5ndGhGaWVsZD0iTm9PZlJlc3VsdHMiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0idWE6RGlh"
"Z25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9zIiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkFkZFJlZmVy"
"ZW5jZXNJdGVtIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlNvdXJjZU5vZGVJZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlJlZmVyZW5jZVR5cGVJZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IklzRm9yd2FyZCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iVGFyZ2V0U2VydmVyVXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRhcmdldE5vZGVJZCIgVHlwZU5hbWU9InVhOkV4cGFu"
"ZGVkTm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVGFyZ2V0Tm9kZUNsYXNzIiBUeXBl"
"TmFtZT0idG5zOk5vZGVDbGFzcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9w"
"YzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJBZGRSZWZlcmVuY2VzUmVxdWVzdCIgQmFzZVR5cGU9InVh"
"OkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1ZXN0SGVhZGVyIiBU"
"eXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09m"
"UmVmZXJlbmNlc1RvQWRkIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iUmVmZXJlbmNlc1RvQWRkIiBUeXBlTmFtZT0idG5zOkFkZFJlZmVyZW5jZXNJdGVtIiBM"
"ZW5ndGhGaWVsZD0iTm9PZlJlZmVyZW5jZXNUb0FkZCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5"
"cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJBZGRSZWZlcmVuY2VzUmVzcG9uc2Ui"
"IEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVz"
"cG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJOb09mUmVzdWx0cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlJlc3VsdHMiIFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVs"
"ZD0iTm9PZlJlc3VsdHMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRGlhZ25vc3RpY0lu"
"Zm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25v"
"c3RpY0luZm9zIiBUeXBlTmFtZT0idWE6RGlhZ25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09m"
"RGlhZ25vc3RpY0luZm9zIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IkRlbGV0ZU5vZGVzSXRlbSIgQmFzZVR5cGU9InVhOkV4dGVuc2lv"
"bk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2Rl"
"SWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZWxldGVUYXJnZXRSZWZlcmVuY2VzIiBUeXBl"
"TmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iRGVsZXRlTm9kZXNSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0"
"ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVO"
"YW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOb2Rl"
"c1RvRGVsZXRlIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Tm9kZXNUb0RlbGV0ZSIgVHlwZU5hbWU9InRuczpEZWxldGVOb2Rlc0l0ZW0iIExlbmd0aEZpZWxk"
"PSJOb09mTm9kZXNUb0RlbGV0ZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9w"
"YzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJEZWxldGVOb2Rlc1Jlc3BvbnNlIiBCYXNlVHlwZT0idWE6"
"RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBU"
"eXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9P"
"ZlJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJS"
"ZXN1bHRzIiBUeXBlTmFtZT0idWE6U3RhdHVzQ29kZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZXN1bHRz"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpYWdub3N0aWNJbmZvcyIgVHlw"
"ZU5hbWU9InVhOkRpYWdub3N0aWNJbmZvIiBMZW5ndGhGaWVsZD0iTm9PZkRpYWdub3N0aWNJbmZv"
"cyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBO"
"YW1lPSJEZWxldGVSZWZlcmVuY2VzSXRlbSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTb3VyY2VOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VUeXBlSWQiIFR5cGVOYW1lPSJ1YTpO"
"b2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJc0ZvcndhcmQiIFR5cGVOYW1lPSJvcGM6"
"Qm9vbGVhbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRhcmdldE5vZGVJZCIgVHlwZU5hbWU9"
"InVhOkV4cGFuZGVkTm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVsZXRlQmlkaXJl"
"Y3Rpb25hbCIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlw"
"ZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkRlbGV0ZVJlZmVyZW5jZXNSZXF1ZXN0"
"IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJl"
"cXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ik5vT2ZSZWZlcmVuY2VzVG9EZWxldGUiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VzVG9EZWxldGUiIFR5cGVOYW1lPSJ0bnM6";
    memcpy(xmlValue.data + 136189, buf_28, 4864);
    char *buf_29 = "RGVsZXRlUmVmZXJlbmNlc0l0ZW0iIExlbmd0aEZpZWxkPSJOb09mUmVmZXJlbmNlc1RvRGVsZXRl"
"IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5h"
"bWU9IkRlbGV0ZVJlZmVyZW5jZXNSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVj"
"dCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRuczpS"
"ZXNwb25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZXN1bHRzIiBUeXBl"
"TmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzdWx0cyIgVHlwZU5h"
"bWU9InVhOlN0YXR1c0NvZGUiIExlbmd0aEZpZWxkPSJOb09mUmVzdWx0cyIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJ1YTpEaWFn"
"bm9zdGljSW5mbyIgTGVuZ3RoRmllbGQ9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIC8+DQogIDwvb3Bj"
"OlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iQXR0cmlidXRl"
"V3JpdGVNYXNrIiBMZW5ndGhJbkJpdHM9IjMyIiBJc09wdGlvblNldD0idHJ1ZSI+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVt"
"ZXJhdGVkVmFsdWUgTmFtZT0iQWNjZXNzTGV2ZWwiIFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51"
"bWVyYXRlZFZhbHVlIE5hbWU9IkFycmF5RGltZW5zaW9ucyIgVmFsdWU9IjIiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQnJvd3NlTmFtZSIgVmFsdWU9IjQiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQ29udGFpbnNOb0xvb3BzIiBWYWx1ZT0iOCIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJEYXRhVHlwZSIgVmFsdWU9IjE2IiAvPg0KICAg"
"IDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkRlc2NyaXB0aW9uIiBWYWx1ZT0iMzIiIC8+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iRGlzcGxheU5hbWUiIFZhbHVlPSI2NCIgLz4N"
"CiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJFdmVudE5vdGlmaWVyIiBWYWx1ZT0iMTI4"
"IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkV4ZWN1dGFibGUiIFZhbHVlPSIy"
"NTYiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSGlzdG9yaXppbmciIFZhbHVl"
"PSI1MTIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSW52ZXJzZU5hbWUiIFZh"
"bHVlPSIxMDI0IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IklzQWJzdHJhY3Qi"
"IFZhbHVlPSIyMDQ4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik1pbmltdW1T"
"YW1wbGluZ0ludGVydmFsIiBWYWx1ZT0iNDA5NiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1"
"ZSBOYW1lPSJOb2RlQ2xhc3MiIFZhbHVlPSI4MTkyIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZh"
"bHVlIE5hbWU9Ik5vZGVJZCIgVmFsdWU9IjE2Mzg0IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZh"
"bHVlIE5hbWU9IlN5bW1ldHJpYyIgVmFsdWU9IjMyNzY4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRl"
"ZFZhbHVlIE5hbWU9IlVzZXJBY2Nlc3NMZXZlbCIgVmFsdWU9IjY1NTM2IiAvPg0KICAgIDxvcGM6"
"RW51bWVyYXRlZFZhbHVlIE5hbWU9IlVzZXJFeGVjdXRhYmxlIiBWYWx1ZT0iMTMxMDcyIiAvPg0K"
"ICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlVzZXJXcml0ZU1hc2siIFZhbHVlPSIyNjIx"
"NDQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVmFsdWVSYW5rIiBWYWx1ZT0i"
"NTI0Mjg4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IldyaXRlTWFzayIgVmFs"
"dWU9IjEwNDg1NzYiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVmFsdWVGb3JW"
"YXJpYWJsZVR5cGUiIFZhbHVlPSIyMDk3MTUyIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVl"
"IE5hbWU9IkRhdGFUeXBlRGVmaW5pdGlvbiIgVmFsdWU9IjQxOTQzMDQiIC8+DQogICAgPG9wYzpF"
"bnVtZXJhdGVkVmFsdWUgTmFtZT0iUm9sZVBlcm1pc3Npb25zIiBWYWx1ZT0iODM4ODYwOCIgLz4N"
"CiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJBY2Nlc3NSZXN0cmljdGlvbnMiIFZhbHVl"
"PSIxNjc3NzIxNiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJBY2Nlc3NMZXZl"
"bEV4IiBWYWx1ZT0iMzM1NTQ0MzIiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxv"
"cGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iQnJvd3NlRGlyZWN0aW9uIiBMZW5ndGhJbkJpdHM9IjMy"
"Ij4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJGb3J3YXJkIiBWYWx1ZT0iMCIgLz4N"
"CiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJJbnZlcnNlIiBWYWx1ZT0iMSIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJCb3RoIiBWYWx1ZT0iMiIgLz4NCiAgICA8b3Bj"
"OkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJJbnZhbGlkIiBWYWx1ZT0iMyIgLz4NCiAgPC9vcGM6RW51"
"bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJWaWV3RGVzY3JpcHRp"
"b24iIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Vmlld0lkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVGlt"
"ZXN0YW1wIiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Vmlld1ZlcnNpb24iIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVk"
"VHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkJyb3dzZURlc2NyaXB0aW9uIiBC"
"YXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVJ"
"ZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZURp"
"cmVjdGlvbiIgVHlwZU5hbWU9InRuczpCcm93c2VEaXJlY3Rpb24iIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJSZWZlcmVuY2VUeXBlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJJbmNsdWRlU3VidHlwZXMiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVDbGFzc01hc2siIFR5cGVOYW1lPSJvcGM6VUludDMy"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzdWx0TWFzayIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUg"
"TmFtZT0iQnJvd3NlUmVzdWx0TWFzayIgTGVuZ3RoSW5CaXRzPSIzMiI+DQogICAgPG9wYzpFbnVt"
"ZXJhdGVkVmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVk"
"VmFsdWUgTmFtZT0iUmVmZXJlbmNlVHlwZUlkIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1l";
    memcpy(xmlValue.data + 141053, buf_29, 4864);
    char *buf_30 = "cmF0ZWRWYWx1ZSBOYW1lPSJJc0ZvcndhcmQiIFZhbHVlPSIyIiAvPg0KICAgIDxvcGM6RW51bWVy"
"YXRlZFZhbHVlIE5hbWU9Ik5vZGVDbGFzcyIgVmFsdWU9IjQiIC8+DQogICAgPG9wYzpFbnVtZXJh"
"dGVkVmFsdWUgTmFtZT0iQnJvd3NlTmFtZSIgVmFsdWU9IjgiIC8+DQogICAgPG9wYzpFbnVtZXJh"
"dGVkVmFsdWUgTmFtZT0iRGlzcGxheU5hbWUiIFZhbHVlPSIxNiIgLz4NCiAgICA8b3BjOkVudW1l"
"cmF0ZWRWYWx1ZSBOYW1lPSJUeXBlRGVmaW5pdGlvbiIgVmFsdWU9IjMyIiAvPg0KICAgIDxvcGM6"
"RW51bWVyYXRlZFZhbHVlIE5hbWU9IkFsbCIgVmFsdWU9IjYzIiAvPg0KICAgIDxvcGM6RW51bWVy"
"YXRlZFZhbHVlIE5hbWU9IlJlZmVyZW5jZVR5cGVJbmZvIiBWYWx1ZT0iMyIgLz4NCiAgICA8b3Bj"
"OkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJUYXJnZXRJbmZvIiBWYWx1ZT0iNjAiIC8+DQogIDwvb3Bj"
"OkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUmVmZXJlbmNl"
"RGVzY3JpcHRpb24iIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVmZXJlbmNlVHlwZUlkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iSXNGb3J3YXJkIiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpFeHBhbmRlZE5vZGVJZCIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZU5hbWUiIFR5cGVOYW1lPSJ1YTpRdWFsaWZpZWRO"
"YW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzcGxheU5hbWUiIFR5cGVOYW1lPSJ1YTpM"
"b2NhbGl6ZWRUZXh0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUNsYXNzIiBUeXBlTmFt"
"ZT0idG5zOk5vZGVDbGFzcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlR5cGVEZWZpbml0aW9u"
"IiBUeXBlTmFtZT0idWE6RXhwYW5kZWROb2RlSWQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBl"
"Pg0KDQogIDxvcGM6T3BhcXVlVHlwZSBOYW1lPSJDb250aW51YXRpb25Qb2ludCI+DQogIDwvb3Bj"
"Ok9wYXF1ZVR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJCcm93c2VSZXN1bHQi"
"IEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3Rh"
"dHVzQ29kZSIgVHlwZU5hbWU9InVhOlN0YXR1c0NvZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJDb250aW51YXRpb25Qb2ludCIgVHlwZU5hbWU9Im9wYzpCeXRlU3RyaW5nIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTm9PZlJlZmVyZW5jZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VzIiBUeXBlTmFtZT0idG5zOlJlZmVyZW5jZURl"
"c2NyaXB0aW9uIiBMZW5ndGhGaWVsZD0iTm9PZlJlZmVyZW5jZXMiIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQnJvd3NlUmVxdWVzdCIg"
"QmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1"
"ZXN0SGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJWaWV3IiBUeXBlTmFtZT0idG5zOlZpZXdEZXNjcmlwdGlvbiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlJlcXVlc3RlZE1heFJlZmVyZW5jZXNQZXJOb2RlIiBUeXBlTmFtZT0ib3Bj"
"OlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOb2Rlc1RvQnJvd3NlIiBUeXBl"
"TmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZXNUb0Jyb3dzZSIg"
"VHlwZU5hbWU9InRuczpCcm93c2VEZXNjcmlwdGlvbiIgTGVuZ3RoRmllbGQ9Ik5vT2ZOb2Rlc1Rv"
"QnJvd3NlIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRU"
"eXBlIE5hbWU9IkJyb3dzZVJlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3Bv"
"bnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3VsdHMiIFR5cGVOYW1l"
"PSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRzIiBUeXBlTmFtZT0i"
"dG5zOkJyb3dzZVJlc3VsdCIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZXN1bHRzIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTm9PZkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdu"
"b3N0aWNJbmZvIiBMZW5ndGhGaWVsZD0iTm9PZkRpYWdub3N0aWNJbmZvcyIgLz4NCiAgPC9vcGM6"
"U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJCcm93c2VOZXh0"
"UmVxdWVzdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJSZXF1ZXN0SGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJSZWxlYXNlQ29udGludWF0aW9uUG9pbnRzIiBUeXBlTmFtZT0ib3Bj"
"OkJvb2xlYW4iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mQ29udGludWF0aW9uUG9pbnRz"
"IiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQ29udGludWF0"
"aW9uUG9pbnRzIiBUeXBlTmFtZT0ib3BjOkJ5dGVTdHJpbmciIExlbmd0aEZpZWxkPSJOb09mQ29u"
"dGludWF0aW9uUG9pbnRzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IkJyb3dzZU5leHRSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVu"
"c2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5h"
"bWU9InRuczpSZXNwb25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZXN1"
"bHRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzdWx0"
"cyIgVHlwZU5hbWU9InRuczpCcm93c2VSZXN1bHQiIExlbmd0aEZpZWxkPSJOb09mUmVzdWx0cyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaWFnbm9zdGljSW5mb3MiIFR5cGVO"
"YW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIgTGVuZ3RoRmllbGQ9Ik5vT2ZEaWFnbm9zdGljSW5mb3Mi"
"IC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFt"
"ZT0iUmVsYXRpdmVQYXRoRWxlbWVudCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZWZlcmVuY2VUeXBlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJc0ludmVyc2UiIFR5cGVOYW1lPSJvcGM6Qm9vbGVh"
"biIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkluY2x1ZGVTdWJ0eXBlcyIgVHlwZU5hbWU9Im9w";
    memcpy(xmlValue.data + 145917, buf_30, 4864);
    char *buf_31 = "YzpCb29sZWFuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVGFyZ2V0TmFtZSIgVHlwZU5hbWU9"
"InVhOlF1YWxpZmllZE5hbWUiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iUmVsYXRpdmVQYXRoIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9u"
"T2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZFbGVtZW50cyIgVHlwZU5hbWU9Im9w"
"YzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVsZW1lbnRzIiBUeXBlTmFtZT0idG5z"
"OlJlbGF0aXZlUGF0aEVsZW1lbnQiIExlbmd0aEZpZWxkPSJOb09mRWxlbWVudHMiIC8+DQogIDwv"
"b3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQnJvd3Nl"
"UGF0aCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJTdGFydGluZ05vZGUiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJSZWxhdGl2ZVBhdGgiIFR5cGVOYW1lPSJ0bnM6UmVsYXRpdmVQYXRoIiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkJyb3dzZVBh"
"dGhUYXJnZXQiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iVGFyZ2V0SWQiIFR5cGVOYW1lPSJ1YTpFeHBhbmRlZE5vZGVJZCIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlJlbWFpbmluZ1BhdGhJbmRleCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i"
"QnJvd3NlUGF0aFJlc3VsdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJTdGF0dXNDb2RlIiBUeXBlTmFtZT0idWE6U3RhdHVzQ29kZSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZUYXJnZXRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iVGFyZ2V0cyIgVHlwZU5hbWU9InRuczpCcm93c2VQYXRoVGFy"
"Z2V0IiBMZW5ndGhGaWVsZD0iTm9PZlRhcmdldHMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBl"
"Pg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVHJhbnNsYXRlQnJvd3NlUGF0aHNUb05v"
"ZGVJZHNSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZCcm93c2VQYXRocyIgVHlwZU5hbWU9Im9wYzpJbnQz"
"MiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZVBhdGhzIiBUeXBlTmFtZT0idG5zOkJy"
"b3dzZVBhdGgiIExlbmd0aEZpZWxkPSJOb09mQnJvd3NlUGF0aHMiIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVHJhbnNsYXRlQnJvd3Nl"
"UGF0aHNUb05vZGVJZHNSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRuczpSZXNwb25z"
"ZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZXN1bHRzIiBUeXBlTmFtZT0i"
"b3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzdWx0cyIgVHlwZU5hbWU9InRu"
"czpCcm93c2VQYXRoUmVzdWx0IiBMZW5ndGhGaWVsZD0iTm9PZlJlc3VsdHMiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0idWE6RGlh"
"Z25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9zIiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlZ2lzdGVy"
"Tm9kZXNSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOb2Rlc1RvUmVnaXN0ZXIiIFR5cGVOYW1lPSJvcGM6"
"SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2Rlc1RvUmVnaXN0ZXIiIFR5cGVOYW1l"
"PSJ1YTpOb2RlSWQiIExlbmd0aEZpZWxkPSJOb09mTm9kZXNUb1JlZ2lzdGVyIiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlZ2lzdGVy"
"Tm9kZXNSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5hbWU9InRuczpSZXNwb25zZUhlYWRlciIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZWdpc3RlcmVkTm9kZUlkcyIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlZ2lzdGVyZWROb2RlSWRzIiBU"
"eXBlTmFtZT0idWE6Tm9kZUlkIiBMZW5ndGhGaWVsZD0iTm9PZlJlZ2lzdGVyZWROb2RlSWRzIiAv"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9"
"IlVucmVnaXN0ZXJOb2Rlc1JlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0"
"SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZk5vZGVzVG9VbnJlZ2lzdGVyIiBU"
"eXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZXNUb1VucmVn"
"aXN0ZXIiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIExlbmd0aEZpZWxkPSJOb09mTm9kZXNUb1VucmVn"
"aXN0ZXIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iVW5yZWdpc3Rlck5vZGVzUmVzcG9uc2UiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25P"
"YmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0"
"bnM6UmVzcG9uc2VIZWFkZXIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"T3BhcXVlVHlwZSBOYW1lPSJDb3VudGVyIj4NCiAgPC9vcGM6T3BhcXVlVHlwZT4NCg0KICA8b3Bj"
"Ok9wYXF1ZVR5cGUgTmFtZT0iTnVtZXJpY1JhbmdlIj4NCiAgPC9vcGM6T3BhcXVlVHlwZT4NCg0K"
"ICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkVuZHBvaW50Q29uZmlndXJhdGlvbiIgQmFzZVR5"
"cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJPcGVyYXRpb25U"
"aW1lb3V0IiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVXNl"
"QmluYXJ5RW5jb2RpbmciIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9Ik1heFN0cmluZ0xlbmd0aCIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3Bj";
    memcpy(xmlValue.data + 150781, buf_31, 4864);
    char *buf_32 = "OkZpZWxkIE5hbWU9Ik1heEJ5dGVTdHJpbmdMZW5ndGgiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNYXhBcnJheUxlbmd0aCIgVHlwZU5hbWU9Im9wYzpJbnQz"
"MiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1heE1lc3NhZ2VTaXplIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWF4QnVmZmVyU2l6ZSIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNoYW5uZWxMaWZldGltZSIgVHlw"
"ZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlY3VyaXR5VG9rZW5M"
"aWZldGltZSIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+"
"DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJRdWVyeURhdGFEZXNjcmlwdGlvbiIgQmFz"
"ZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWxhdGl2"
"ZVBhdGgiIFR5cGVOYW1lPSJ0bnM6UmVsYXRpdmVQYXRoIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iQXR0cmlidXRlSWQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iSW5kZXhSYW5nZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iTm9kZVR5cGVEZXNjcmlw"
"dGlvbiIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJUeXBlRGVmaW5pdGlvbk5vZGUiIFR5cGVOYW1lPSJ1YTpFeHBhbmRlZE5vZGVJZCIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkluY2x1ZGVTdWJUeXBlcyIgVHlwZU5hbWU9Im9wYzpCb29sZWFu"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkRhdGFUb1JldHVybiIgVHlwZU5hbWU9Im9w"
"YzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFUb1JldHVybiIgVHlwZU5hbWU9"
"InRuczpRdWVyeURhdGFEZXNjcmlwdGlvbiIgTGVuZ3RoRmllbGQ9Ik5vT2ZEYXRhVG9SZXR1cm4i"
"IC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFt"
"ZT0iRmlsdGVyT3BlcmF0b3IiIExlbmd0aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRl"
"ZFZhbHVlIE5hbWU9IkVxdWFscyIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFs"
"dWUgTmFtZT0iSXNOdWxsIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBO"
"YW1lPSJHcmVhdGVyVGhhbiIgVmFsdWU9IjIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUg"
"TmFtZT0iTGVzc1RoYW4iIFZhbHVlPSIzIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5h"
"bWU9IkdyZWF0ZXJUaGFuT3JFcXVhbCIgVmFsdWU9IjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVk"
"VmFsdWUgTmFtZT0iTGVzc1RoYW5PckVxdWFsIiBWYWx1ZT0iNSIgLz4NCiAgICA8b3BjOkVudW1l"
"cmF0ZWRWYWx1ZSBOYW1lPSJMaWtlIiBWYWx1ZT0iNiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRW"
"YWx1ZSBOYW1lPSJOb3QiIFZhbHVlPSI3IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5h"
"bWU9IkJldHdlZW4iIFZhbHVlPSI4IiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9"
"IkluTGlzdCIgVmFsdWU9IjkiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQW5k"
"IiBWYWx1ZT0iMTAiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iT3IiIFZhbHVl"
"PSIxMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJDYXN0IiBWYWx1ZT0iMTIi"
"IC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iSW5WaWV3IiBWYWx1ZT0iMTMiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iT2ZUeXBlIiBWYWx1ZT0iMTQiIC8+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUmVsYXRlZFRvIiBWYWx1ZT0iMTUiIC8+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQml0d2lzZUFuZCIgVmFsdWU9IjE2IiAvPg0K"
"ICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkJpdHdpc2VPciIgVmFsdWU9IjE3IiAvPg0K"
"ICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlF1"
"ZXJ5RGF0YVNldCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpFeHBhbmRlZE5vZGVJZCIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlR5cGVEZWZpbml0aW9uTm9kZSIgVHlwZU5hbWU9InVhOkV4cGFuZGVkTm9k"
"ZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlZhbHVlcyIgVHlwZU5hbWU9Im9wYzpJ"
"bnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlZhbHVlcyIgVHlwZU5hbWU9InVhOlZhcmlh"
"bnQiIExlbmd0aEZpZWxkPSJOb09mVmFsdWVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4N"
"Cg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik5vZGVSZWZlcmVuY2UiIEJhc2VUeXBlPSJ1"
"YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUlkIiBUeXBlTmFt"
"ZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVmZXJlbmNlVHlwZUlkIiBU"
"eXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSXNGb3J3YXJkIiBU"
"eXBlTmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUmVmZXJl"
"bmNlZE5vZGVJZHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJSZWZlcmVuY2VkTm9kZUlkcyIgVHlwZU5hbWU9InVhOk5vZGVJZCIgTGVuZ3RoRmllbGQ9Ik5v"
"T2ZSZWZlcmVuY2VkTm9kZUlkcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9w"
"YzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJDb250ZW50RmlsdGVyRWxlbWVudCIgQmFzZVR5cGU9InVh"
"OkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJGaWx0ZXJPcGVyYXRvciIg"
"VHlwZU5hbWU9InRuczpGaWx0ZXJPcGVyYXRvciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5v"
"T2ZGaWx0ZXJPcGVyYW5kcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkZpbHRlck9wZXJhbmRzIiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiBMZW5n"
"dGhGaWVsZD0iTm9PZkZpbHRlck9wZXJhbmRzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4N"
"Cg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkNvbnRlbnRGaWx0ZXIiIEJhc2VUeXBlPSJ1"
"YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkVsZW1lbnRzIiBU"
"eXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRWxlbWVudHMiIFR5"
"cGVOYW1lPSJ0bnM6Q29udGVudEZpbHRlckVsZW1lbnQiIExlbmd0aEZpZWxkPSJOb09mRWxlbWVu"
"dHMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUg";
    memcpy(xmlValue.data + 155645, buf_32, 4864);
    char *buf_33 = "TmFtZT0iRmlsdGVyT3BlcmFuZCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogIDwv"
"b3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRWxlbWVu"
"dE9wZXJhbmQiIEJhc2VUeXBlPSJ0bnM6RmlsdGVyT3BlcmFuZCI+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJJbmRleCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRU"
"eXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iTGl0ZXJhbE9wZXJhbmQiIEJhc2VU"
"eXBlPSJ0bnM6RmlsdGVyT3BlcmFuZCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJWYWx1ZSIgVHlw"
"ZU5hbWU9InVhOlZhcmlhbnQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iQXR0cmlidXRlT3BlcmFuZCIgQmFzZVR5cGU9InRuczpGaWx0"
"ZXJPcGVyYW5kIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVJZCIgVHlwZU5hbWU9InVhOk5v"
"ZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkFsaWFzIiBUeXBlTmFtZT0ib3BjOlN0cmlu"
"ZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZVBhdGgiIFR5cGVOYW1lPSJ0bnM6UmVs"
"YXRpdmVQYXRoIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQXR0cmlidXRlSWQiIFR5cGVOYW1l"
"PSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSW5kZXhSYW5nZSIgVHlwZU5h"
"bWU9Im9wYzpTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iU2ltcGxlQXR0cmlidXRlT3BlcmFuZCIgQmFzZVR5cGU9InRuczpG"
"aWx0ZXJPcGVyYW5kIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlR5cGVEZWZpbml0aW9uSWQiIFR5"
"cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mQnJvd3NlUGF0"
"aCIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZVBh"
"dGgiIFR5cGVOYW1lPSJ1YTpRdWFsaWZpZWROYW1lIiBMZW5ndGhGaWVsZD0iTm9PZkJyb3dzZVBh"
"dGgiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBdHRyaWJ1dGVJZCIgVHlwZU5hbWU9Im9wYzpV"
"SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJbmRleFJhbmdlIiBUeXBlTmFtZT0ib3Bj"
"OlN0cmluZyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVk"
"VHlwZSBOYW1lPSJDb250ZW50RmlsdGVyRWxlbWVudFJlc3VsdCIgQmFzZVR5cGU9InVhOkV4dGVu"
"c2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdGF0dXNDb2RlIiBUeXBlTmFtZT0i"
"dWE6U3RhdHVzQ29kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZPcGVyYW5kU3RhdHVz"
"Q29kZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJPcGVy"
"YW5kU3RhdHVzQ29kZXMiIFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVsZD0iTm9P"
"Zk9wZXJhbmRTdGF0dXNDb2RlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZPcGVyYW5k"
"RGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iT3BlcmFuZERpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdub3N0aWNJbmZv"
"IiBMZW5ndGhGaWVsZD0iTm9PZk9wZXJhbmREaWFnbm9zdGljSW5mb3MiIC8+DQogIDwvb3BjOlN0"
"cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQ29udGVudEZpbHRl"
"clJlc3VsdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJOb09mRWxlbWVudFJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJFbGVtZW50UmVzdWx0cyIgVHlwZU5hbWU9InRuczpDb250ZW50RmlsdGVy"
"RWxlbWVudFJlc3VsdCIgTGVuZ3RoRmllbGQ9Ik5vT2ZFbGVtZW50UmVzdWx0cyIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9Ik5vT2ZFbGVtZW50RGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRWxlbWVudERpYWdub3N0aWNJbmZvcyIg"
"VHlwZU5hbWU9InVhOkRpYWdub3N0aWNJbmZvIiBMZW5ndGhGaWVsZD0iTm9PZkVsZW1lbnREaWFn"
"bm9zdGljSW5mb3MiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0"
"dXJlZFR5cGUgTmFtZT0iUGFyc2luZ1Jlc3VsdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVj"
"dCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdGF0dXNDb2RlIiBUeXBlTmFtZT0idWE6U3RhdHVz"
"Q29kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEYXRhU3RhdHVzQ29kZXMiIFR5cGVO"
"YW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEYXRhU3RhdHVzQ29kZXMi"
"IFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVsZD0iTm9PZkRhdGFTdGF0dXNDb2Rl"
"cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEYXRhRGlhZ25vc3RpY0luZm9zIiBUeXBl"
"TmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YURpYWdub3N0aWNJ"
"bmZvcyIgVHlwZU5hbWU9InVhOkRpYWdub3N0aWNJbmZvIiBMZW5ndGhGaWVsZD0iTm9PZkRhdGFE"
"aWFnbm9zdGljSW5mb3MiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iUXVlcnlGaXJzdFJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNp"
"b25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9"
"InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVmlldyIgVHlwZU5h"
"bWU9InRuczpWaWV3RGVzY3JpcHRpb24iIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTm9k"
"ZVR5cGVzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9k"
"ZVR5cGVzIiBUeXBlTmFtZT0idG5zOk5vZGVUeXBlRGVzY3JpcHRpb24iIExlbmd0aEZpZWxkPSJO"
"b09mTm9kZVR5cGVzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRmlsdGVyIiBUeXBlTmFtZT0i"
"dG5zOkNvbnRlbnRGaWx0ZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNYXhEYXRhU2V0c1Rv"
"UmV0dXJuIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1h"
"eFJlZmVyZW5jZXNUb1JldHVybiIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogIDwvb3BjOlN0"
"cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUXVlcnlGaXJzdFJl"
"c3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iTm9PZlF1ZXJ5RGF0YVNldHMiIFR5cGVOYW1lPSJvcGM6SW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJRdWVyeURhdGFTZXRzIiBUeXBlTmFtZT0idG5zOlF1";
    memcpy(xmlValue.data + 160509, buf_33, 4864);
    char *buf_34 = "ZXJ5RGF0YVNldCIgTGVuZ3RoRmllbGQ9Ik5vT2ZRdWVyeURhdGFTZXRzIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iQ29udGludWF0aW9uUG9pbnQiIFR5cGVOYW1lPSJvcGM6Qnl0ZVN0cmluZyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZQYXJzaW5nUmVzdWx0cyIgVHlwZU5hbWU9Im9w"
"YzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlBhcnNpbmdSZXN1bHRzIiBUeXBlTmFt"
"ZT0idG5zOlBhcnNpbmdSZXN1bHQiIExlbmd0aEZpZWxkPSJOb09mUGFyc2luZ1Jlc3VsdHMiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFt"
"ZT0idWE6RGlhZ25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9zIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRmlsdGVyUmVzdWx0IiBUeXBlTmFtZT0idG5zOkNvbnRl"
"bnRGaWx0ZXJSZXN1bHQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iUXVlcnlOZXh0UmVxdWVzdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lv"
"bk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1ZXN0SGVhZGVyIiBUeXBlTmFtZT0i"
"dG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWxlYXNlQ29udGlu"
"dWF0aW9uUG9pbnQiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IkNvbnRpbnVhdGlvblBvaW50IiBUeXBlTmFtZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogIDwv"
"b3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUXVlcnlO"
"ZXh0UmVzcG9uc2UiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUXVlcnlEYXRhU2V0cyIgVHlwZU5hbWU9Im9wYzpJ"
"bnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlF1ZXJ5RGF0YVNldHMiIFR5cGVOYW1lPSJ0"
"bnM6UXVlcnlEYXRhU2V0IiBMZW5ndGhGaWVsZD0iTm9PZlF1ZXJ5RGF0YVNldHMiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJSZXZpc2VkQ29udGludWF0aW9uUG9pbnQiIFR5cGVOYW1lPSJvcGM6"
"Qnl0ZVN0cmluZyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJh"
"dGVkVHlwZSBOYW1lPSJUaW1lc3RhbXBzVG9SZXR1cm4iIExlbmd0aEluQml0cz0iMzIiPg0KICAg"
"IDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNvdXJjZSIgVmFsdWU9IjAiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU2VydmVyIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVu"
"dW1lcmF0ZWRWYWx1ZSBOYW1lPSJCb3RoIiBWYWx1ZT0iMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0"
"ZWRWYWx1ZSBOYW1lPSJOZWl0aGVyIiBWYWx1ZT0iMyIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRW"
"YWx1ZSBOYW1lPSJJbnZhbGlkIiBWYWx1ZT0iNCIgLz4NCiAgPC9vcGM6RW51bWVyYXRlZFR5cGU+"
"DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJSZWFkVmFsdWVJZCIgQmFzZVR5cGU9InVh"
"OkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1l"
"PSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBdHRyaWJ1dGVJZCIgVHlwZU5h"
"bWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJbmRleFJhbmdlIiBUeXBl"
"TmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFFbmNvZGluZyIg"
"VHlwZU5hbWU9InVhOlF1YWxpZmllZE5hbWUiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0K"
"DQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUmVhZFJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpF"
"eHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlw"
"ZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWF4QWdl"
"IiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRpbWVzdGFt"
"cHNUb1JldHVybiIgVHlwZU5hbWU9InRuczpUaW1lc3RhbXBzVG9SZXR1cm4iIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJOb09mTm9kZXNUb1JlYWQiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJOb2Rlc1RvUmVhZCIgVHlwZU5hbWU9InRuczpSZWFkVmFsdWVJ"
"ZCIgTGVuZ3RoRmllbGQ9Ik5vT2ZOb2Rlc1RvUmVhZCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5"
"cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJSZWFkUmVzcG9uc2UiIEJhc2VUeXBl"
"PSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzcG9uc2VIZWFk"
"ZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJOb09mUmVzdWx0cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlc3VsdHMiIFR5cGVOYW1lPSJ1YTpEYXRhVmFsdWUiIExlbmd0aEZpZWxkPSJOb09mUmVz"
"dWx0cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIFR5cGVO"
"YW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaWFnbm9zdGljSW5mb3Mi"
"IFR5cGVOYW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIgTGVuZ3RoRmllbGQ9Ik5vT2ZEaWFnbm9zdGlj"
"SW5mb3MiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iSGlzdG9yeVJlYWRWYWx1ZUlkIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVJZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkluZGV4UmFuZ2UiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGF0YUVuY29kaW5nIiBUeXBlTmFtZT0idWE6UXVhbGlm"
"aWVkTmFtZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNvbnRpbnVhdGlvblBvaW50IiBUeXBl"
"TmFtZT0ib3BjOkJ5dGVTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxv"
"cGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeVJlYWRSZXN1bHQiIEJhc2VUeXBlPSJ1YTpF"
"eHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3RhdHVzQ29kZSIgVHlwZU5h"
"bWU9InVhOlN0YXR1c0NvZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDb250aW51YXRpb25Q"
"b2ludCIgVHlwZU5hbWU9Im9wYzpCeXRlU3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"SGlzdG9yeURhdGEiIFR5cGVOYW1lPSJ1YTpFeHRlbnNpb25PYmplY3QiIC8+DQogIDwvb3BjOlN0"
"cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeVJlYWRE";
    memcpy(xmlValue.data + 165373, buf_34, 4864);
    char *buf_35 = "ZXRhaWxzIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgPC9vcGM6U3RydWN0dXJl"
"ZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJSZWFkRXZlbnREZXRhaWxzIiBC"
"YXNlVHlwZT0idG5zOkhpc3RvcnlSZWFkRGV0YWlscyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJO"
"dW1WYWx1ZXNQZXJOb2RlIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlN0YXJ0VGltZSIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IkVuZFRpbWUiIFR5cGVOYW1lPSJvcGM6RGF0ZVRpbWUiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJGaWx0ZXIiIFR5cGVOYW1lPSJ0bnM6RXZlbnRGaWx0ZXIiIC8+DQogIDwvb3Bj"
"OlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iUmVhZFJhd01v"
"ZGlmaWVkRGV0YWlscyIgQmFzZVR5cGU9InRuczpIaXN0b3J5UmVhZERldGFpbHMiPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iSXNSZWFkTW9kaWZpZWQiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IlN0YXJ0VGltZSIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuZFRpbWUiIFR5cGVOYW1lPSJvcGM6RGF0ZVRpbWUi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOdW1WYWx1ZXNQZXJOb2RlIiBUeXBlTmFtZT0ib3Bj"
"OlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJldHVybkJvdW5kcyIgVHlwZU5hbWU9"
"Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVj"
"dHVyZWRUeXBlIE5hbWU9IlJlYWRQcm9jZXNzZWREZXRhaWxzIiBCYXNlVHlwZT0idG5zOkhpc3Rv"
"cnlSZWFkRGV0YWlscyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdGFydFRpbWUiIFR5cGVOYW1l"
"PSJvcGM6RGF0ZVRpbWUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbmRUaW1lIiBUeXBlTmFt"
"ZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUHJvY2Vzc2luZ0ludGVy"
"dmFsIiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZB"
"Z2dyZWdhdGVUeXBlIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iQWdncmVnYXRlVHlwZSIgVHlwZU5hbWU9InVhOk5vZGVJZCIgTGVuZ3RoRmllbGQ9Ik5vT2ZB"
"Z2dyZWdhdGVUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWdncmVnYXRlQ29uZmlndXJh"
"dGlvbiIgVHlwZU5hbWU9InRuczpBZ2dyZWdhdGVDb25maWd1cmF0aW9uIiAvPg0KICA8L29wYzpT"
"dHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlYWRBdFRpbWVE"
"ZXRhaWxzIiBCYXNlVHlwZT0idG5zOkhpc3RvcnlSZWFkRGV0YWlscyI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOb09mUmVxVGltZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJSZXFUaW1lcyIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgTGVuZ3RoRmllbGQ9"
"Ik5vT2ZSZXFUaW1lcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZVNpbXBsZUJvdW5kcyIg"
"VHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJlYWRBbm5vdGF0aW9uRGF0YURldGFpbHMiIEJhc2VU"
"eXBlPSJ0bnM6SGlzdG9yeVJlYWREZXRhaWxzIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZS"
"ZXFUaW1lcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJl"
"cVRpbWVzIiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiBMZW5ndGhGaWVsZD0iTm9PZlJlcVRpbWVz"
"IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5h"
"bWU9Ikhpc3RvcnlEYXRhIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5vT2ZEYXRhVmFsdWVzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iRGF0YVZhbHVlcyIgVHlwZU5hbWU9InVhOkRhdGFWYWx1ZSIgTGVu"
"Z3RoRmllbGQ9Ik5vT2ZEYXRhVmFsdWVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0K"
"ICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik1vZGlmaWNhdGlvbkluZm8iIEJhc2VUeXBlPSJ1"
"YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTW9kaWZpY2F0aW9uVGlt"
"ZSIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVwZGF0"
"ZVR5cGUiIFR5cGVOYW1lPSJ0bnM6SGlzdG9yeVVwZGF0ZVR5cGUiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJVc2VyTmFtZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeU1vZGlmaWVk"
"RGF0YSIgQmFzZVR5cGU9InRuczpIaXN0b3J5RGF0YSI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJO"
"b09mRGF0YVZhbHVlcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IkRhdGFWYWx1ZXMiIFR5cGVOYW1lPSJ1YTpEYXRhVmFsdWUiIExlbmd0aEZpZWxkPSJOb09m"
"RGF0YVZhbHVlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZNb2RpZmljYXRpb25JbmZv"
"cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1vZGlmaWNh"
"dGlvbkluZm9zIiBUeXBlTmFtZT0idG5zOk1vZGlmaWNhdGlvbkluZm8iIExlbmd0aEZpZWxkPSJO"
"b09mTW9kaWZpY2F0aW9uSW5mb3MiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxv"
"cGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeUV2ZW50IiBCYXNlVHlwZT0idWE6RXh0ZW5z"
"aW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZFdmVudHMiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFdmVudHMiIFR5cGVOYW1lPSJ0bnM6"
"SGlzdG9yeUV2ZW50RmllbGRMaXN0IiBMZW5ndGhGaWVsZD0iTm9PZkV2ZW50cyIgLz4NCiAgPC9v"
"cGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJIaXN0b3J5"
"UmVhZFJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iSGlzdG9yeVJlYWREZXRhaWxzIiBUeXBlTmFtZT0idWE6RXh0"
"ZW5zaW9uT2JqZWN0IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVGltZXN0YW1wc1RvUmV0dXJu"
"IiBUeXBlTmFtZT0idG5zOlRpbWVzdGFtcHNUb1JldHVybiIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlbGVhc2VDb250aW51YXRpb25Qb2ludHMiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZOb2Rlc1RvUmVhZCIgVHlwZU5hbWU9Im9wYzpJbnQz";
    memcpy(xmlValue.data + 170237, buf_35, 4864);
    char *buf_36 = "MiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vZGVzVG9SZWFkIiBUeXBlTmFtZT0idG5zOkhp"
"c3RvcnlSZWFkVmFsdWVJZCIgTGVuZ3RoRmllbGQ9Ik5vT2ZOb2Rlc1RvUmVhZCIgLz4NCiAgPC9v"
"cGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJIaXN0b3J5"
"UmVhZFJlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRzIiBUeXBlTmFtZT0idG5zOkhpc3RvcnlS"
"ZWFkUmVzdWx0IiBMZW5ndGhGaWVsZD0iTm9PZlJlc3VsdHMiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0idWE6RGlhZ25vc3RpY0lu"
"Zm8iIExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9zIiAvPg0KICA8L29wYzpTdHJ1Y3R1"
"cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IldyaXRlVmFsdWUiIEJhc2VU"
"eXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUlkIiBU"
"eXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQXR0cmlidXRlSWQi"
"IFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSW5kZXhSYW5n"
"ZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJWYWx1ZSIg"
"VHlwZU5hbWU9InVhOkRhdGFWYWx1ZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAg"
"PG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJXcml0ZVJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRl"
"bnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5h"
"bWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZk5vZGVz"
"VG9Xcml0ZSIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5v"
"ZGVzVG9Xcml0ZSIgVHlwZU5hbWU9InRuczpXcml0ZVZhbHVlIiBMZW5ndGhGaWVsZD0iTm9PZk5v"
"ZGVzVG9Xcml0ZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1"
"cmVkVHlwZSBOYW1lPSJXcml0ZVJlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJl"
"c3BvbnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3VsdHMiIFR5cGVO"
"YW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRzIiBUeXBlTmFt"
"ZT0idWE6U3RhdHVzQ29kZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZXN1bHRzIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTm9PZkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdu"
"b3N0aWNJbmZvIiBMZW5ndGhGaWVsZD0iTm9PZkRpYWdub3N0aWNJbmZvcyIgLz4NCiAgPC9vcGM6"
"U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJIaXN0b3J5VXBk"
"YXRlRGV0YWlscyIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogIDwvb3BjOlN0cnVjdHVy"
"ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iSGlzdG9yeVVwZGF0ZVR5cGUi"
"IExlbmd0aEluQml0cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ikluc2Vy"
"dCIgVmFsdWU9IjEiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUmVwbGFjZSIg"
"VmFsdWU9IjIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVXBkYXRlIiBWYWx1"
"ZT0iMyIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJEZWxldGUiIFZhbHVlPSI0"
"IiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5h"
"bWU9IlBlcmZvcm1VcGRhdGVUeXBlIiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1l"
"cmF0ZWRWYWx1ZSBOYW1lPSJJbnNlcnQiIFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRl"
"ZFZhbHVlIE5hbWU9IlJlcGxhY2UiIFZhbHVlPSIyIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZh"
"bHVlIE5hbWU9IlVwZGF0ZSIgVmFsdWU9IjMiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUg"
"TmFtZT0iUmVtb3ZlIiBWYWx1ZT0iNCIgLz4NCiAgPC9vcGM6RW51bWVyYXRlZFR5cGU+DQoNCiAg"
"PG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJVcGRhdGVEYXRhRGV0YWlscyIgQmFzZVR5cGU9InRu"
"czpIaXN0b3J5VXBkYXRlRGV0YWlscyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5"
"cGVOYW1lPSJ1YTpOb2RlSWQiIFNvdXJjZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0YWlscyIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlBlcmZvcm1JbnNlcnRSZXBsYWNlIiBUeXBlTmFtZT0i"
"dG5zOlBlcmZvcm1VcGRhdGVUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlVwZGF0"
"ZVZhbHVlcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVw"
"ZGF0ZVZhbHVlcyIgVHlwZU5hbWU9InVhOkRhdGFWYWx1ZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZVcGRh"
"dGVWYWx1ZXMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJl"
"ZFR5cGUgTmFtZT0iVXBkYXRlU3RydWN0dXJlRGF0YURldGFpbHMiIEJhc2VUeXBlPSJ0bnM6SGlz"
"dG9yeVVwZGF0ZURldGFpbHMiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9kZUlkIiBUeXBlTmFt"
"ZT0idWE6Tm9kZUlkIiBTb3VyY2VUeXBlPSJ0bnM6SGlzdG9yeVVwZGF0ZURldGFpbHMiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJQZXJmb3JtSW5zZXJ0UmVwbGFjZSIgVHlwZU5hbWU9InRuczpQ"
"ZXJmb3JtVXBkYXRlVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZVcGRhdGVWYWx1"
"ZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVcGRhdGVW"
"YWx1ZXMiIFR5cGVOYW1lPSJ1YTpEYXRhVmFsdWUiIExlbmd0aEZpZWxkPSJOb09mVXBkYXRlVmFs"
"dWVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9IlVwZGF0ZUV2ZW50RGV0YWlscyIgQmFzZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0"
"YWlscyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQi"
"IFNvdXJjZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0YWlscyIgLz4NCiAgICA8b3BjOkZpZWxk";
    memcpy(xmlValue.data + 175101, buf_36, 4864);
    char *buf_37 = "IE5hbWU9IlBlcmZvcm1JbnNlcnRSZXBsYWNlIiBUeXBlTmFtZT0idG5zOlBlcmZvcm1VcGRhdGVU"
"eXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRmlsdGVyIiBUeXBlTmFtZT0idG5zOkV2ZW50"
"RmlsdGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkV2ZW50RGF0YSIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkV2ZW50RGF0YSIgVHlwZU5hbWU9"
"InRuczpIaXN0b3J5RXZlbnRGaWVsZExpc3QiIExlbmd0aEZpZWxkPSJOb09mRXZlbnREYXRhIiAv"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9"
"IkRlbGV0ZVJhd01vZGlmaWVkRGV0YWlscyIgQmFzZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0"
"YWlscyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQi"
"IFNvdXJjZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0YWlscyIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IklzRGVsZXRlTW9kaWZpZWQiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IlN0YXJ0VGltZSIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkVuZFRpbWUiIFR5cGVOYW1lPSJvcGM6RGF0ZVRpbWUiIC8+DQog"
"IDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRGVs"
"ZXRlQXRUaW1lRGV0YWlscyIgQmFzZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0YWlscyI+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIFNvdXJjZVR5"
"cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0YWlscyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5v"
"T2ZSZXFUaW1lcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlJlcVRpbWVzIiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiBMZW5ndGhGaWVsZD0iTm9PZlJlcVRp"
"bWVzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9IkRlbGV0ZUV2ZW50RGV0YWlscyIgQmFzZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0"
"YWlscyI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb2RlSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQi"
"IFNvdXJjZVR5cGU9InRuczpIaXN0b3J5VXBkYXRlRGV0YWlscyIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9Ik5vT2ZFdmVudElkcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IkV2ZW50SWRzIiBUeXBlTmFtZT0ib3BjOkJ5dGVTdHJpbmciIExlbmd0aEZpZWxk"
"PSJOb09mRXZlbnRJZHMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeVVwZGF0ZVJlc3VsdCIgQmFzZVR5cGU9InVhOkV4dGVu"
"c2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdGF0dXNDb2RlIiBUeXBlTmFtZT0i"
"dWE6U3RhdHVzQ29kZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZPcGVyYXRpb25SZXN1"
"bHRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iT3BlcmF0"
"aW9uUmVzdWx0cyIgVHlwZU5hbWU9InVhOlN0YXR1c0NvZGUiIExlbmd0aEZpZWxkPSJOb09mT3Bl"
"cmF0aW9uUmVzdWx0cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEaWFnbm9zdGljSW5m"
"b3MiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaWFnbm9z"
"dGljSW5mb3MiIFR5cGVOYW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIgTGVuZ3RoRmllbGQ9Ik5vT2ZE"
"aWFnbm9zdGljSW5mb3MiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeVVwZGF0ZVJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRl"
"bnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5h"
"bWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkhpc3Rv"
"cnlVcGRhdGVEZXRhaWxzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iSGlzdG9yeVVwZGF0ZURldGFpbHMiIFR5cGVOYW1lPSJ1YTpFeHRlbnNpb25PYmplY3Qi"
"IExlbmd0aEZpZWxkPSJOb09mSGlzdG9yeVVwZGF0ZURldGFpbHMiIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeVVwZGF0ZVJl"
"c3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRzIiBUeXBlTmFtZT0idG5zOkhpc3RvcnlVcGRhdGVS"
"ZXN1bHQiIExlbmd0aEZpZWxkPSJOb09mUmVzdWx0cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIg"
"TGVuZ3RoRmllbGQ9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRU"
"eXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQ2FsbE1ldGhvZFJlcXVlc3QiIEJh"
"c2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iT2JqZWN0"
"SWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNZXRob2RJ"
"ZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZJbnB1"
"dEFyZ3VtZW50cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IklucHV0QXJndW1lbnRzIiBUeXBlTmFtZT0idWE6VmFyaWFudCIgTGVuZ3RoRmllbGQ9Ik5vT2ZJ"
"bnB1dEFyZ3VtZW50cyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1"
"Y3R1cmVkVHlwZSBOYW1lPSJDYWxsTWV0aG9kUmVzdWx0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9u"
"T2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN0YXR1c0NvZGUiIFR5cGVOYW1lPSJ1YTpT"
"dGF0dXNDb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZklucHV0QXJndW1lbnRSZXN1"
"bHRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSW5wdXRB"
"cmd1bWVudFJlc3VsdHMiIFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVsZD0iTm9P"
"ZklucHV0QXJndW1lbnRSZXN1bHRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZklucHV0"
"QXJndW1lbnREaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJJbnB1dEFyZ3VtZW50RGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0idWE6";
    memcpy(xmlValue.data + 179965, buf_37, 4864);
    char *buf_38 = "RGlhZ25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09mSW5wdXRBcmd1bWVudERpYWdub3N0aWNJ"
"bmZvcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZPdXRwdXRBcmd1bWVudHMiIFR5cGVO"
"YW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJPdXRwdXRBcmd1bWVudHMi"
"IFR5cGVOYW1lPSJ1YTpWYXJpYW50IiBMZW5ndGhGaWVsZD0iTm9PZk91dHB1dEFyZ3VtZW50cyIg"
"Lz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1l"
"PSJDYWxsUmVxdWVzdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJSZXF1ZXN0SGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTWV0aG9kc1RvQ2FsbCIgVHlwZU5hbWU9Im9wYzpJ"
"bnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1ldGhvZHNUb0NhbGwiIFR5cGVOYW1lPSJ0"
"bnM6Q2FsbE1ldGhvZFJlcXVlc3QiIExlbmd0aEZpZWxkPSJOb09mTWV0aG9kc1RvQ2FsbCIgLz4N"
"CiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJD"
"YWxsUmVzcG9uc2UiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUmVzdWx0cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3VsdHMiIFR5cGVOYW1lPSJ0bnM6Q2FsbE1ldGhv"
"ZFJlc3VsdCIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZXN1bHRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iTm9PZkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdub3N0aWNJbmZv"
"IiBMZW5ndGhGaWVsZD0iTm9PZkRpYWdub3N0aWNJbmZvcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJl"
"ZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVkVHlwZSBOYW1lPSJNb25pdG9yaW5nTW9kZSIgTGVu"
"Z3RoSW5CaXRzPSIzMiI+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iRGlzYWJsZWQi"
"IFZhbHVlPSIwIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlNhbXBsaW5nIiBW"
"YWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJSZXBvcnRpbmciIFZh"
"bHVlPSIyIiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0KICA8b3BjOkVudW1lcmF0ZWRU"
"eXBlIE5hbWU9IkRhdGFDaGFuZ2VUcmlnZ2VyIiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3Bj"
"OkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJTdGF0dXMiIFZhbHVlPSIwIiAvPg0KICAgIDxvcGM6RW51"
"bWVyYXRlZFZhbHVlIE5hbWU9IlN0YXR1c1ZhbHVlIiBWYWx1ZT0iMSIgLz4NCiAgICA8b3BjOkVu"
"dW1lcmF0ZWRWYWx1ZSBOYW1lPSJTdGF0dXNWYWx1ZVRpbWVzdGFtcCIgVmFsdWU9IjIiIC8+DQog"
"IDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iRGVh"
"ZGJhbmRUeXBlIiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBO"
"YW1lPSJOb25lIiBWYWx1ZT0iMCIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJB"
"YnNvbHV0ZSIgVmFsdWU9IjEiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUGVy"
"Y2VudCIgVmFsdWU9IjIiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iTW9uaXRvcmluZ0ZpbHRlciIgQmFzZVR5cGU9InVhOkV4dGVuc2lv"
"bk9iamVjdCI+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5"
"cGUgTmFtZT0iRGF0YUNoYW5nZUZpbHRlciIgQmFzZVR5cGU9InRuczpNb25pdG9yaW5nRmlsdGVy"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRyaWdnZXIiIFR5cGVOYW1lPSJ0bnM6RGF0YUNoYW5n"
"ZVRyaWdnZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZWFkYmFuZFR5cGUiIFR5cGVOYW1l"
"PSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVhZGJhbmRWYWx1ZSIgVHlw"
"ZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iRXZlbnRGaWx0ZXIiIEJhc2VUeXBlPSJ0bnM6TW9uaXRvcmlu"
"Z0ZpbHRlciI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mU2VsZWN0Q2xhdXNlcyIgVHlwZU5h"
"bWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlbGVjdENsYXVzZXMiIFR5"
"cGVOYW1lPSJ0bnM6U2ltcGxlQXR0cmlidXRlT3BlcmFuZCIgTGVuZ3RoRmllbGQ9Ik5vT2ZTZWxl"
"Y3RDbGF1c2VzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iV2hlcmVDbGF1c2UiIFR5cGVOYW1l"
"PSJ0bnM6Q29udGVudEZpbHRlciIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9w"
"YzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJBZ2dyZWdhdGVDb25maWd1cmF0aW9uIiBCYXNlVHlwZT0i"
"dWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlVzZVNlcnZlckNhcGFi"
"aWxpdGllc0RlZmF1bHRzIiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJUcmVhdFVuY2VydGFpbkFzQmFkIiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4iIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJQZXJjZW50RGF0YUJhZCIgVHlwZU5hbWU9Im9wYzpCeXRlIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUGVyY2VudERhdGFHb29kIiBUeXBlTmFtZT0ib3BjOkJ5"
"dGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VTbG9wZWRFeHRyYXBvbGF0aW9uIiBUeXBl"
"TmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6"
"U3RydWN0dXJlZFR5cGUgTmFtZT0iQWdncmVnYXRlRmlsdGVyIiBCYXNlVHlwZT0idG5zOk1vbml0"
"b3JpbmdGaWx0ZXIiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3RhcnRUaW1lIiBUeXBlTmFtZT0i"
"b3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQWdncmVnYXRlVHlwZSIgVHlw"
"ZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlByb2Nlc3NpbmdJbnRl"
"cnZhbCIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBZ2dy"
"ZWdhdGVDb25maWd1cmF0aW9uIiBUeXBlTmFtZT0idG5zOkFnZ3JlZ2F0ZUNvbmZpZ3VyYXRpb24i"
"IC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFt"
"ZT0iTW9uaXRvcmluZ0ZpbHRlclJlc3VsdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i"
"RXZlbnRGaWx0ZXJSZXN1bHQiIEJhc2VUeXBlPSJ0bnM6TW9uaXRvcmluZ0ZpbHRlclJlc3VsdCI+";
    memcpy(xmlValue.data + 184829, buf_38, 4864);
    char *buf_39 = "DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mU2VsZWN0Q2xhdXNlUmVzdWx0cyIgVHlwZU5hbWU9"
"Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlbGVjdENsYXVzZVJlc3VsdHMi"
"IFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVsZD0iTm9PZlNlbGVjdENsYXVzZVJl"
"c3VsdHMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mU2VsZWN0Q2xhdXNlRGlhZ25vc3Rp"
"Y0luZm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vs"
"ZWN0Q2xhdXNlRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0idWE6RGlhZ25vc3RpY0luZm8iIExl"
"bmd0aEZpZWxkPSJOb09mU2VsZWN0Q2xhdXNlRGlhZ25vc3RpY0luZm9zIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iV2hlcmVDbGF1c2VSZXN1bHQiIFR5cGVOYW1lPSJ0bnM6Q29udGVudEZpbHRl"
"clJlc3VsdCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVk"
"VHlwZSBOYW1lPSJBZ2dyZWdhdGVGaWx0ZXJSZXN1bHQiIEJhc2VUeXBlPSJ0bnM6TW9uaXRvcmlu"
"Z0ZpbHRlclJlc3VsdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXZpc2VkU3RhcnRUaW1lIiBU"
"eXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmV2aXNlZFBy"
"b2Nlc3NpbmdJbnRlcnZhbCIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJSZXZpc2VkQWdncmVnYXRlQ29uZmlndXJhdGlvbiIgVHlwZU5hbWU9InRuczpBZ2dy"
"ZWdhdGVDb25maWd1cmF0aW9uIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3Bj"
"OlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik1vbml0b3JpbmdQYXJhbWV0ZXJzIiBCYXNlVHlwZT0idWE6"
"RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNsaWVudEhhbmRsZSIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTYW1wbGluZ0ludGVy"
"dmFsIiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkZpbHRl"
"ciIgVHlwZU5hbWU9InVhOkV4dGVuc2lvbk9iamVjdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlF1ZXVlU2l6ZSIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJEaXNjYXJkT2xkZXN0IiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogIDwvb3BjOlN0cnVj"
"dHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iTW9uaXRvcmVkSXRlbUNy"
"ZWF0ZVJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iSXRlbVRvTW9uaXRvciIgVHlwZU5hbWU9InRuczpSZWFkVmFsdWVJZCIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik1vbml0b3JpbmdNb2RlIiBUeXBlTmFtZT0idG5zOk1vbml0b3Jp"
"bmdNb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdGVkUGFyYW1ldGVycyIgVHlw"
"ZU5hbWU9InRuczpNb25pdG9yaW5nUGFyYW1ldGVycyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5"
"cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJNb25pdG9yZWRJdGVtQ3JlYXRlUmVz"
"dWx0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlN0YXR1c0NvZGUiIFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iTW9uaXRvcmVkSXRlbUlkIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlJldmlzZWRTYW1wbGluZ0ludGVydmFsIiBUeXBlTmFtZT0ib3BjOkRvdWJs"
"ZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJldmlzZWRRdWV1ZVNpemUiIFR5cGVOYW1lPSJv"
"cGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRmlsdGVyUmVzdWx0IiBUeXBlTmFt"
"ZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkNyZWF0ZU1vbml0b3JlZEl0ZW1zUmVxdWVzdCIgQmFz"
"ZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXF1ZXN0"
"SGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJTdWJzY3JpcHRpb25JZCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJUaW1lc3RhbXBzVG9SZXR1cm4iIFR5cGVOYW1lPSJ0bnM6VGltZXN0YW1wc1Rv"
"UmV0dXJuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkl0ZW1zVG9DcmVhdGUiIFR5cGVO"
"YW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJdGVtc1RvQ3JlYXRlIiBU"
"eXBlTmFtZT0idG5zOk1vbml0b3JlZEl0ZW1DcmVhdGVSZXF1ZXN0IiBMZW5ndGhGaWVsZD0iTm9P"
"Zkl0ZW1zVG9DcmVhdGUiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3Ry"
"dWN0dXJlZFR5cGUgTmFtZT0iQ3JlYXRlTW9uaXRvcmVkSXRlbXNSZXNwb25zZSIgQmFzZVR5cGU9"
"InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRl"
"ciIgVHlwZU5hbWU9InRuczpSZXNwb25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik5vT2ZSZXN1bHRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iUmVzdWx0cyIgVHlwZU5hbWU9InRuczpNb25pdG9yZWRJdGVtQ3JlYXRlUmVzdWx0IiBMZW5n"
"dGhGaWVsZD0iTm9PZlJlc3VsdHMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRGlhZ25v"
"c3RpY0luZm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"RGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0idWE6RGlhZ25vc3RpY0luZm8iIExlbmd0aEZpZWxk"
"PSJOb09mRGlhZ25vc3RpY0luZm9zIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8"
"b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik1vbml0b3JlZEl0ZW1Nb2RpZnlSZXF1ZXN0IiBCYXNl"
"VHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1vbml0b3Jl"
"ZEl0ZW1JZCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJS"
"ZXF1ZXN0ZWRQYXJhbWV0ZXJzIiBUeXBlTmFtZT0idG5zOk1vbml0b3JpbmdQYXJhbWV0ZXJzIiAv"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9"
"Ik1vbml0b3JlZEl0ZW1Nb2RpZnlSZXN1bHQiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3Qi"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3RhdHVzQ29kZSIgVHlwZU5hbWU9InVhOlN0YXR1c0Nv"
"ZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXZpc2VkU2FtcGxpbmdJbnRlcnZhbCIgVHlw"
"ZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXZpc2VkUXVldWVT"
"aXplIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkZpbHRl";
    memcpy(xmlValue.data + 189693, buf_39, 4864);
    char *buf_40 = "clJlc3VsdCIgVHlwZU5hbWU9InVhOkV4dGVuc2lvbk9iamVjdCIgLz4NCiAgPC9vcGM6U3RydWN0"
"dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJNb2RpZnlNb25pdG9yZWRJ"
"dGVtc1JlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iU3Vic2NyaXB0aW9uSWQiIFR5cGVOYW1lPSJvcGM6VUludDMy"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVGltZXN0YW1wc1RvUmV0dXJuIiBUeXBlTmFtZT0i"
"dG5zOlRpbWVzdGFtcHNUb1JldHVybiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZJdGVt"
"c1RvTW9kaWZ5IiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"SXRlbXNUb01vZGlmeSIgVHlwZU5hbWU9InRuczpNb25pdG9yZWRJdGVtTW9kaWZ5UmVxdWVzdCIg"
"TGVuZ3RoRmllbGQ9Ik5vT2ZJdGVtc1RvTW9kaWZ5IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlw"
"ZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik1vZGlmeU1vbml0b3JlZEl0ZW1zUmVz"
"cG9uc2UiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJOb09mUmVzdWx0cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IlJlc3VsdHMiIFR5cGVOYW1lPSJ0bnM6TW9uaXRvcmVkSXRlbU1v"
"ZGlmeVJlc3VsdCIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZXN1bHRzIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iTm9PZkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdub3N0aWNJ"
"bmZvIiBMZW5ndGhGaWVsZD0iTm9PZkRpYWdub3N0aWNJbmZvcyIgLz4NCiAgPC9vcGM6U3RydWN0"
"dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTZXRNb25pdG9yaW5nTW9k"
"ZVJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iU3Vic2NyaXB0aW9uSWQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTW9uaXRvcmluZ01vZGUiIFR5cGVOYW1lPSJ0bnM6TW9u"
"aXRvcmluZ01vZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTW9uaXRvcmVkSXRlbUlk"
"cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1vbml0b3Jl"
"ZEl0ZW1JZHMiIFR5cGVOYW1lPSJvcGM6VUludDMyIiBMZW5ndGhGaWVsZD0iTm9PZk1vbml0b3Jl"
"ZEl0ZW1JZHMiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJl"
"ZFR5cGUgTmFtZT0iU2V0TW9uaXRvcmluZ01vZGVSZXNwb25zZSIgQmFzZVR5cGU9InVhOkV4dGVu"
"c2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRlciIgVHlwZU5h"
"bWU9InRuczpSZXNwb25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZSZXN1"
"bHRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzdWx0"
"cyIgVHlwZU5hbWU9InVhOlN0YXR1c0NvZGUiIExlbmd0aEZpZWxkPSJOb09mUmVzdWx0cyIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJvcGM6"
"SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1l"
"PSJ1YTpEaWFnbm9zdGljSW5mbyIgTGVuZ3RoRmllbGQ9Ik5vT2ZEaWFnbm9zdGljSW5mb3MiIC8+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i"
"U2V0VHJpZ2dlcmluZ1JlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVh"
"ZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3Vic2NyaXB0aW9uSWQiIFR5cGVOYW1lPSJv"
"cGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVHJpZ2dlcmluZ0l0ZW1JZCIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTGlua3NUb0Fk"
"ZCIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkxpbmtzVG9B"
"ZGQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiBMZW5ndGhGaWVsZD0iTm9PZkxpbmtzVG9BZGQiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTGlua3NUb1JlbW92ZSIgVHlwZU5hbWU9Im9wYzpJ"
"bnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkxpbmtzVG9SZW1vdmUiIFR5cGVOYW1lPSJv"
"cGM6VUludDMyIiBMZW5ndGhGaWVsZD0iTm9PZkxpbmtzVG9SZW1vdmUiIC8+DQogIDwvb3BjOlN0"
"cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iU2V0VHJpZ2dlcmlu"
"Z1Jlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkFkZFJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBZGRSZXN1bHRzIiBUeXBlTmFtZT0idWE6U3RhdHVz"
"Q29kZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZBZGRSZXN1bHRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iTm9PZkFkZERpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IkFkZERpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdub3N0"
"aWNJbmZvIiBMZW5ndGhGaWVsZD0iTm9PZkFkZERpYWdub3N0aWNJbmZvcyIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9Ik5vT2ZSZW1vdmVSZXN1bHRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iUmVtb3ZlUmVzdWx0cyIgVHlwZU5hbWU9InVhOlN0YXR1c0Nv"
"ZGUiIExlbmd0aEZpZWxkPSJOb09mUmVtb3ZlUmVzdWx0cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9Ik5vT2ZSZW1vdmVEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZW1vdmVEaWFnbm9zdGljSW5mb3MiIFR5cGVOYW1lPSJ1YTpE"
"aWFnbm9zdGljSW5mbyIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZW1vdmVEaWFnbm9zdGljSW5mb3MiIC8+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i"
"RGVsZXRlTW9uaXRvcmVkSXRlbXNSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0";
    memcpy(xmlValue.data + 194557, buf_40, 4864);
    char *buf_41 = "Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVx"
"dWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN1YnNjcmlwdGlvbklkIiBUeXBl"
"TmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZNb25pdG9yZWRJ"
"dGVtSWRzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTW9u"
"aXRvcmVkSXRlbUlkcyIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIExlbmd0aEZpZWxkPSJOb09mTW9u"
"aXRvcmVkSXRlbUlkcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1"
"Y3R1cmVkVHlwZSBOYW1lPSJEZWxldGVNb25pdG9yZWRJdGVtc1Jlc3BvbnNlIiBCYXNlVHlwZT0i"
"dWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVy"
"IiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Tm9PZlJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJSZXN1bHRzIiBUeXBlTmFtZT0idWE6U3RhdHVzQ29kZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZXN1"
"bHRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkRpYWdub3N0aWNJbmZvcyIgVHlwZU5h"
"bWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpYWdub3N0aWNJbmZvcyIg"
"VHlwZU5hbWU9InVhOkRpYWdub3N0aWNJbmZvIiBMZW5ndGhGaWVsZD0iTm9PZkRpYWdub3N0aWNJ"
"bmZvcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlw"
"ZSBOYW1lPSJDcmVhdGVTdWJzY3JpcHRpb25SZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9u"
"T2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0"
"bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RlZFB1Ymxp"
"c2hpbmdJbnRlcnZhbCIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJSZXF1ZXN0ZWRMaWZldGltZUNvdW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RlZE1heEtlZXBBbGl2ZUNvdW50IiBUeXBlTmFtZT0i"
"b3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1heE5vdGlmaWNhdGlvbnNQZXJQ"
"dWJsaXNoIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlB1"
"Ymxpc2hpbmdFbmFibGVkIiBUeXBlTmFtZT0ib3BjOkJvb2xlYW4iIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJQcmlvcml0eSIgVHlwZU5hbWU9Im9wYzpCeXRlIiAvPg0KICA8L29wYzpTdHJ1Y3R1"
"cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkNyZWF0ZVN1YnNjcmlwdGlv"
"blJlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iU3Vic2NyaXB0aW9uSWQiIFR5cGVOYW1lPSJvcGM6VUludDMy"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmV2aXNlZFB1Ymxpc2hpbmdJbnRlcnZhbCIgVHlw"
"ZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXZpc2VkTGlmZXRp"
"bWVDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJS"
"ZXZpc2VkTWF4S2VlcEFsaXZlQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICA8L29w"
"YzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik1vZGlmeVN1"
"YnNjcmlwdGlvblJlcXVlc3QiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRlciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVy"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3Vic2NyaXB0aW9uSWQiIFR5cGVOYW1lPSJvcGM6"
"VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdGVkUHVibGlzaGluZ0ludGVy"
"dmFsIiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVl"
"c3RlZExpZmV0aW1lQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iUmVxdWVzdGVkTWF4S2VlcEFsaXZlQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMy"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWF4Tm90aWZpY2F0aW9uc1BlclB1Ymxpc2giIFR5"
"cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUHJpb3JpdHkiIFR5"
"cGVOYW1lPSJvcGM6Qnl0ZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpT"
"dHJ1Y3R1cmVkVHlwZSBOYW1lPSJNb2RpZnlTdWJzY3JpcHRpb25SZXNwb25zZSIgQmFzZVR5cGU9"
"InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXNwb25zZUhlYWRl"
"ciIgVHlwZU5hbWU9InRuczpSZXNwb25zZUhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlJldmlzZWRQdWJsaXNoaW5nSW50ZXJ2YWwiIFR5cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iUmV2aXNlZExpZmV0aW1lQ291bnQiIFR5cGVOYW1lPSJvcGM6VUlu"
"dDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmV2aXNlZE1heEtlZXBBbGl2ZUNvdW50IiBU"
"eXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9w"
"YzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTZXRQdWJsaXNoaW5nTW9kZVJlcXVlc3QiIEJhc2VUeXBl"
"PSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVxdWVzdEhlYWRl"
"ciIgVHlwZU5hbWU9InRuczpSZXF1ZXN0SGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"UHVibGlzaGluZ0VuYWJsZWQiIFR5cGVOYW1lPSJvcGM6Qm9vbGVhbiIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ik5vT2ZTdWJzY3JpcHRpb25JZHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJTdWJzY3JpcHRpb25JZHMiIFR5cGVOYW1lPSJvcGM6VUludDMy"
"IiBMZW5ndGhGaWVsZD0iTm9PZlN1YnNjcmlwdGlvbklkcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJl"
"ZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTZXRQdWJsaXNoaW5nTW9kZVJl"
"c3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRzIiBUeXBlTmFtZT0idWE6U3RhdHVzQ29kZSIgTGVu"
"Z3RoRmllbGQ9Ik5vT2ZSZXN1bHRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkRpYWdu";
    memcpy(xmlValue.data + 199421, buf_41, 4864);
    char *buf_42 = "b3N0aWNJbmZvcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdub3N0aWNJbmZvIiBMZW5ndGhGaWVs"
"ZD0iTm9PZkRpYWdub3N0aWNJbmZvcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAg"
"PG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJOb3RpZmljYXRpb25NZXNzYWdlIiBCYXNlVHlwZT0i"
"dWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcXVlbmNlTnVtYmVy"
"IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlB1Ymxpc2hU"
"aW1lIiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9P"
"Zk5vdGlmaWNhdGlvbkRhdGEiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJOb3RpZmljYXRpb25EYXRhIiBUeXBlTmFtZT0idWE6RXh0ZW5zaW9uT2JqZWN0IiBM"
"ZW5ndGhGaWVsZD0iTm9PZk5vdGlmaWNhdGlvbkRhdGEiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRU"
"eXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iTm90aWZpY2F0aW9uRGF0YSIgQmFz"
"ZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQog"
"IDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iRGF0YUNoYW5nZU5vdGlmaWNhdGlvbiIgQmFzZVR5"
"cGU9InRuczpOb3RpZmljYXRpb25EYXRhIj4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZNb25p"
"dG9yZWRJdGVtcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"Ik1vbml0b3JlZEl0ZW1zIiBUeXBlTmFtZT0idG5zOk1vbml0b3JlZEl0ZW1Ob3RpZmljYXRpb24i"
"IExlbmd0aEZpZWxkPSJOb09mTW9uaXRvcmVkSXRlbXMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0idWE6RGlhZ25vc3RpY0luZm8i"
"IExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9zIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVk"
"VHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9Ik1vbml0b3JlZEl0ZW1Ob3RpZmlj"
"YXRpb24iIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iQ2xpZW50SGFuZGxlIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlZhbHVlIiBUeXBlTmFtZT0idWE6RGF0YVZhbHVlIiAvPg0KICA8L29wYzpTdHJ1Y3R1"
"cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IkV2ZW50Tm90aWZpY2F0aW9u"
"TGlzdCIgQmFzZVR5cGU9InRuczpOb3RpZmljYXRpb25EYXRhIj4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9Ik5vT2ZFdmVudHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJFdmVudHMiIFR5cGVOYW1lPSJ0bnM6RXZlbnRGaWVsZExpc3QiIExlbmd0aEZpZWxkPSJO"
"b09mRXZlbnRzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVy"
"ZWRUeXBlIE5hbWU9IkV2ZW50RmllbGRMaXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNsaWVudEhhbmRsZSIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRXZlbnRGaWVsZHMiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFdmVudEZpZWxkcyIgVHlwZU5hbWU9"
"InVhOlZhcmlhbnQiIExlbmd0aEZpZWxkPSJOb09mRXZlbnRGaWVsZHMiIC8+DQogIDwvb3BjOlN0"
"cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iSGlzdG9yeUV2ZW50"
"RmllbGRMaXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9Ik5vT2ZFdmVudEZpZWxkcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IkV2ZW50RmllbGRzIiBUeXBlTmFtZT0idWE6VmFyaWFudCIgTGVuZ3RoRmll"
"bGQ9Ik5vT2ZFdmVudEZpZWxkcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9w"
"YzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTdGF0dXNDaGFuZ2VOb3RpZmljYXRpb24iIEJhc2VUeXBl"
"PSJ0bnM6Tm90aWZpY2F0aW9uRGF0YSI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdGF0dXMiIFR5"
"cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3Rp"
"Y0luZm8iIFR5cGVOYW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIgLz4NCiAgPC9vcGM6U3RydWN0dXJl"
"ZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTdWJzY3JpcHRpb25BY2tub3ds"
"ZWRnZW1lbnQiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iU3Vic2NyaXB0aW9uSWQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iU2VxdWVuY2VOdW1iZXIiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICA8"
"L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlB1Ymxp"
"c2hSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTdWJzY3JpcHRpb25BY2tub3dsZWRnZW1lbnRzIiBUeXBl"
"TmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3Vic2NyaXB0aW9uQWNr"
"bm93bGVkZ2VtZW50cyIgVHlwZU5hbWU9InRuczpTdWJzY3JpcHRpb25BY2tub3dsZWRnZW1lbnQi"
"IExlbmd0aEZpZWxkPSJOb09mU3Vic2NyaXB0aW9uQWNrbm93bGVkZ2VtZW50cyIgLz4NCiAgPC9v"
"cGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJQdWJsaXNo"
"UmVzcG9uc2UiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJTdWJzY3JpcHRpb25JZCIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mQXZhaWxhYmxlU2VxdWVuY2VOdW1iZXJzIiBU"
"eXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQXZhaWxhYmxlU2Vx"
"dWVuY2VOdW1iZXJzIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgTGVuZ3RoRmllbGQ9Ik5vT2ZBdmFp"
"bGFibGVTZXF1ZW5jZU51bWJlcnMiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNb3JlTm90aWZp"
"Y2F0aW9ucyIgVHlwZU5hbWU9Im9wYzpCb29sZWFuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Tm90aWZpY2F0aW9uTWVzc2FnZSIgVHlwZU5hbWU9InRuczpOb3RpZmljYXRpb25NZXNzYWdlIiAv";
    memcpy(xmlValue.data + 204285, buf_42, 4864);
    char *buf_43 = "Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3VsdHMiIFR5cGVOYW1lPSJvcGM6SW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRzIiBUeXBlTmFtZT0idWE6U3RhdHVzQ29k"
"ZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZSZXN1bHRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9P"
"ZkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkRpYWdub3N0aWNJbmZvcyIgVHlwZU5hbWU9InVhOkRpYWdub3N0aWNJbmZvIiBMZW5n"
"dGhGaWVsZD0iTm9PZkRpYWdub3N0aWNJbmZvcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+"
"DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJSZXB1Ymxpc2hSZXF1ZXN0IiBCYXNlVHlw"
"ZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RIZWFk"
"ZXIiIFR5cGVOYW1lPSJ0bnM6UmVxdWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IlN1YnNjcmlwdGlvbklkIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlJldHJhbnNtaXRTZXF1ZW5jZU51bWJlciIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+"
"DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0i"
"UmVwdWJsaXNoUmVzcG9uc2UiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6UmVzcG9uc2VIZWFk"
"ZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb3RpZmljYXRpb25NZXNzYWdlIiBUeXBlTmFt"
"ZT0idG5zOk5vdGlmaWNhdGlvbk1lc3NhZ2UiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0K"
"DQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVHJhbnNmZXJSZXN1bHQiIEJhc2VUeXBlPSJ1"
"YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3RhdHVzQ29kZSIgVHlw"
"ZU5hbWU9InVhOlN0YXR1c0NvZGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mQXZhaWxh"
"YmxlU2VxdWVuY2VOdW1iZXJzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iQXZhaWxhYmxlU2VxdWVuY2VOdW1iZXJzIiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIg"
"TGVuZ3RoRmllbGQ9Ik5vT2ZBdmFpbGFibGVTZXF1ZW5jZU51bWJlcnMiIC8+DQogIDwvb3BjOlN0"
"cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iVHJhbnNmZXJTdWJz"
"Y3JpcHRpb25zUmVxdWVzdCIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJSZXF1ZXN0SGVhZGVyIiBUeXBlTmFtZT0idG5zOlJlcXVlc3RIZWFkZXIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mU3Vic2NyaXB0aW9uSWRzIiBUeXBlTmFtZT0i"
"b3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3Vic2NyaXB0aW9uSWRzIiBUeXBl"
"TmFtZT0ib3BjOlVJbnQzMiIgTGVuZ3RoRmllbGQ9Ik5vT2ZTdWJzY3JpcHRpb25JZHMiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJTZW5kSW5pdGlhbFZhbHVlcyIgVHlwZU5hbWU9Im9wYzpCb29s"
"ZWFuIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBl"
"IE5hbWU9IlRyYW5zZmVyU3Vic2NyaXB0aW9uc1Jlc3BvbnNlIiBCYXNlVHlwZT0idWE6RXh0ZW5z"
"aW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3BvbnNlSGVhZGVyIiBUeXBlTmFt"
"ZT0idG5zOlJlc3BvbnNlSGVhZGVyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZlJlc3Vs"
"dHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZXN1bHRz"
"IiBUeXBlTmFtZT0idG5zOlRyYW5zZmVyUmVzdWx0IiBMZW5ndGhGaWVsZD0iTm9PZlJlc3VsdHMi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0i"
"b3BjOkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBl"
"TmFtZT0idWE6RGlhZ25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9z"
"IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5h"
"bWU9IkRlbGV0ZVN1YnNjcmlwdGlvbnNSZXF1ZXN0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2Jq"
"ZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcXVlc3RIZWFkZXIiIFR5cGVOYW1lPSJ0bnM6"
"UmVxdWVzdEhlYWRlciIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZTdWJzY3JpcHRpb25J"
"ZHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTdWJzY3Jp"
"cHRpb25JZHMiIFR5cGVOYW1lPSJvcGM6VUludDMyIiBMZW5ndGhGaWVsZD0iTm9PZlN1YnNjcmlw"
"dGlvbklkcyIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVk"
"VHlwZSBOYW1lPSJEZWxldGVTdWJzY3JpcHRpb25zUmVzcG9uc2UiIEJhc2VUeXBlPSJ1YTpFeHRl"
"bnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVzcG9uc2VIZWFkZXIiIFR5cGVO"
"YW1lPSJ0bnM6UmVzcG9uc2VIZWFkZXIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mUmVz"
"dWx0cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlc3Vs"
"dHMiIFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiBMZW5ndGhGaWVsZD0iTm9PZlJlc3VsdHMiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm9zIiBUeXBlTmFt"
"ZT0idWE6RGlhZ25vc3RpY0luZm8iIExlbmd0aEZpZWxkPSJOb09mRGlhZ25vc3RpY0luZm9zIiAv"
"Pg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9"
"IkJ1aWxkSW5mbyIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJQcm9kdWN0VXJpIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ik1hbnVmYWN0dXJlck5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iUHJvZHVjdE5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iU29mdHdhcmVWZXJzaW9uIiBUeXBlTmFtZT0ib3BjOlN0cmlu"
"ZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJ1aWxkTnVtYmVyIiBUeXBlTmFtZT0ib3BjOlN0"
"cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJ1aWxkRGF0ZSIgVHlwZU5hbWU9Im9wYzpE"
"YXRlVGltZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVk"
"VHlwZSBOYW1lPSJSZWR1bmRhbmN5U3VwcG9ydCIgTGVuZ3RoSW5CaXRzPSIzMiI+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTm9uZSIgVmFsdWU9IjAiIC8+DQogICAgPG9wYzpFbnVt";
    memcpy(xmlValue.data + 209149, buf_43, 4864);
    char *buf_44 = "ZXJhdGVkVmFsdWUgTmFtZT0iQ29sZCIgVmFsdWU9IjEiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVk"
"VmFsdWUgTmFtZT0iV2FybSIgVmFsdWU9IjIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUg"
"TmFtZT0iSG90IiBWYWx1ZT0iMyIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJU"
"cmFuc3BhcmVudCIgVmFsdWU9IjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0i"
"SG90QW5kTWlycm9yZWQiIFZhbHVlPSI1IiAvPg0KICA8L29wYzpFbnVtZXJhdGVkVHlwZT4NCg0K"
"ICA8b3BjOkVudW1lcmF0ZWRUeXBlIE5hbWU9IlNlcnZlclN0YXRlIiBMZW5ndGhJbkJpdHM9IjMy"
"Ij4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJSdW5uaW5nIiBWYWx1ZT0iMCIgLz4N"
"CiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJGYWlsZWQiIFZhbHVlPSIxIiAvPg0KICAg"
"IDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik5vQ29uZmlndXJhdGlvbiIgVmFsdWU9IjIiIC8+"
"DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iU3VzcGVuZGVkIiBWYWx1ZT0iMyIgLz4N"
"CiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJTaHV0ZG93biIgVmFsdWU9IjQiIC8+DQog"
"ICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVGVzdCIgVmFsdWU9IjUiIC8+DQogICAgPG9w"
"YzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iQ29tbXVuaWNhdGlvbkZhdWx0IiBWYWx1ZT0iNiIgLz4N"
"CiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJVbmtub3duIiBWYWx1ZT0iNyIgLz4NCiAg"
"PC9vcGM6RW51bWVyYXRlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJSZWR1"
"bmRhbnRTZXJ2ZXJEYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJTZXJ2ZXJJZCIgVHlwZU5hbWU9Im9wYzpTdHJpbmciIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJTZXJ2aWNlTGV2ZWwiIFR5cGVOYW1lPSJvcGM6Qnl0ZSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlclN0YXRlIiBUeXBlTmFtZT0idG5zOlNlcnZlclN0YXRl"
"IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5h"
"bWU9IkVuZHBvaW50VXJsTGlzdERhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0"
"Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZFbmRwb2ludFVybExpc3QiIFR5cGVOYW1lPSJv"
"cGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbmRwb2ludFVybExpc3QiIFR5cGVO"
"YW1lPSJvcGM6U3RyaW5nIiBMZW5ndGhGaWVsZD0iTm9PZkVuZHBvaW50VXJsTGlzdCIgLz4NCiAg"
"PC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJOZXR3"
"b3JrR3JvdXBEYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJTZXJ2ZXJVcmkiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTm9PZk5ldHdvcmtQYXRocyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5ldHdvcmtQYXRocyIgVHlwZU5hbWU9InRuczpFbmRwb2lu"
"dFVybExpc3REYXRhVHlwZSIgTGVuZ3RoRmllbGQ9Ik5vT2ZOZXR3b3JrUGF0aHMiIC8+DQogIDwv"
"b3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iU2FtcGxp"
"bmdJbnRlcnZhbERpYWdub3N0aWNzRGF0YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmpl"
"Y3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2FtcGxpbmdJbnRlcnZhbCIgVHlwZU5hbWU9Im9w"
"YzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJNb25pdG9yZWRJdGVtQ291bnQiIFR5"
"cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWF4TW9uaXRvcmVk"
"SXRlbUNvdW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IkRpc2FibGVkTW9uaXRvcmVkSXRlbUNvdW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAg"
"PC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTZXJ2"
"ZXJEaWFnbm9zdGljc1N1bW1hcnlEYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVj"
"dCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXJ2ZXJWaWV3Q291bnQiIFR5cGVOYW1lPSJvcGM6"
"VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQ3VycmVudFNlc3Npb25Db3VudCIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDdW11bGF0ZWRTZXNz"
"aW9uQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"U2VjdXJpdHlSZWplY3RlZFNlc3Npb25Db3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJSZWplY3RlZFNlc3Npb25Db3VudCIgVHlwZU5hbWU9Im9wYzpV"
"SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZXNzaW9uVGltZW91dENvdW50IiBUeXBl"
"TmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlc3Npb25BYm9ydENv"
"dW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkN1cnJl"
"bnRTdWJzY3JpcHRpb25Db3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpG"
"aWVsZCBOYW1lPSJDdW11bGF0ZWRTdWJzY3JpcHRpb25Db3VudCIgVHlwZU5hbWU9Im9wYzpVSW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQdWJsaXNoaW5nSW50ZXJ2YWxDb3VudCIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTZWN1cml0eVJlamVj"
"dGVkUmVxdWVzdHNDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJSZWplY3RlZFJlcXVlc3RzQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0K"
"ICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlNl"
"cnZlclN0YXR1c0RhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IlN0YXJ0VGltZSIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IkN1cnJlbnRUaW1lIiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAv"
"Pg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU3RhdGUiIFR5cGVOYW1lPSJ0bnM6U2VydmVyU3RhdGUi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJCdWlsZEluZm8iIFR5cGVOYW1lPSJ0bnM6QnVpbGRJ"
"bmZvIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vjb25kc1RpbGxTaHV0ZG93biIgVHlwZU5h"
"bWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJTaHV0ZG93blJlYXNvbiIg"
"VHlwZU5hbWU9InVhOkxvY2FsaXplZFRleHQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0K"
"DQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iU2Vzc2lvbkRpYWdub3N0aWNzRGF0YVR5cGUi";
    memcpy(xmlValue.data + 214013, buf_44, 4864);
    char *buf_45 = "IEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vz"
"c2lvbklkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vz"
"c2lvbk5hbWUiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"Q2xpZW50RGVzY3JpcHRpb24iIFR5cGVOYW1lPSJ0bnM6QXBwbGljYXRpb25EZXNjcmlwdGlvbiIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlcnZlclVyaSIgVHlwZU5hbWU9Im9wYzpTdHJpbmci"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJFbmRwb2ludFVybCIgVHlwZU5hbWU9Im9wYzpTdHJp"
"bmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJOb09mTG9jYWxlSWRzIiBUeXBlTmFtZT0ib3Bj"
"OkludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTG9jYWxlSWRzIiBUeXBlTmFtZT0ib3Bj"
"OlN0cmluZyIgTGVuZ3RoRmllbGQ9Ik5vT2ZMb2NhbGVJZHMiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJBY3R1YWxTZXNzaW9uVGltZW91dCIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAg"
"PG9wYzpGaWVsZCBOYW1lPSJNYXhSZXNwb25zZU1lc3NhZ2VTaXplIiBUeXBlTmFtZT0ib3BjOlVJ"
"bnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNsaWVudENvbm5lY3Rpb25UaW1lIiBUeXBl"
"TmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQ2xpZW50TGFzdENv"
"bnRhY3RUaW1lIiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iQ3VycmVudFN1YnNjcmlwdGlvbnNDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJDdXJyZW50TW9uaXRvcmVkSXRlbXNDb3VudCIgVHlwZU5hbWU9"
"Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDdXJyZW50UHVibGlzaFJlcXVl"
"c3RzSW5RdWV1ZSIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1l"
"PSJUb3RhbFJlcXVlc3RDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFUeXBl"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iVW5hdXRob3JpemVkUmVxdWVzdENvdW50IiBUeXBl"
"TmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlYWRDb3VudCIgVHlw"
"ZU5hbWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iSGlzdG9yeVJlYWRDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFUeXBl"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iV3JpdGVDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2"
"aWNlQ291bnRlckRhdGFUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iSGlzdG9yeVVwZGF0"
"ZUNvdW50IiBUeXBlTmFtZT0idG5zOlNlcnZpY2VDb3VudGVyRGF0YVR5cGUiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJDYWxsQ291bnQiIFR5cGVOYW1lPSJ0bnM6U2VydmljZUNvdW50ZXJEYXRh"
"VHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkNyZWF0ZU1vbml0b3JlZEl0ZW1zQ291bnQi"
"IFR5cGVOYW1lPSJ0bnM6U2VydmljZUNvdW50ZXJEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9Ik1vZGlmeU1vbml0b3JlZEl0ZW1zQ291bnQiIFR5cGVOYW1lPSJ0bnM6U2VydmljZUNv"
"dW50ZXJEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNldE1vbml0b3JpbmdNb2Rl"
"Q291bnQiIFR5cGVOYW1lPSJ0bnM6U2VydmljZUNvdW50ZXJEYXRhVHlwZSIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlNldFRyaWdnZXJpbmdDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNlQ291"
"bnRlckRhdGFUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGVsZXRlTW9uaXRvcmVkSXRl"
"bXNDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFUeXBlIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iQ3JlYXRlU3Vic2NyaXB0aW9uQ291bnQiIFR5cGVOYW1lPSJ0bnM6U2Vy"
"dmljZUNvdW50ZXJEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik1vZGlmeVN1YnNj"
"cmlwdGlvbkNvdW50IiBUeXBlTmFtZT0idG5zOlNlcnZpY2VDb3VudGVyRGF0YVR5cGUiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJTZXRQdWJsaXNoaW5nTW9kZUNvdW50IiBUeXBlTmFtZT0idG5z"
"OlNlcnZpY2VDb3VudGVyRGF0YVR5cGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQdWJsaXNo"
"Q291bnQiIFR5cGVOYW1lPSJ0bnM6U2VydmljZUNvdW50ZXJEYXRhVHlwZSIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IlJlcHVibGlzaENvdW50IiBUeXBlTmFtZT0idG5zOlNlcnZpY2VDb3VudGVy"
"RGF0YVR5cGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUcmFuc2ZlclN1YnNjcmlwdGlvbnND"
"b3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFUeXBlIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iRGVsZXRlU3Vic2NyaXB0aW9uc0NvdW50IiBUeXBlTmFtZT0idG5zOlNlcnZp"
"Y2VDb3VudGVyRGF0YVR5cGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBZGROb2Rlc0NvdW50"
"IiBUeXBlTmFtZT0idG5zOlNlcnZpY2VDb3VudGVyRGF0YVR5cGUiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJBZGRSZWZlcmVuY2VzQ291bnQiIFR5cGVOYW1lPSJ0bnM6U2VydmljZUNvdW50ZXJE"
"YXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRlbGV0ZU5vZGVzQ291bnQiIFR5cGVO"
"YW1lPSJ0bnM6U2VydmljZUNvdW50ZXJEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9"
"IkRlbGV0ZVJlZmVyZW5jZXNDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFU"
"eXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQnJvd3NlQ291bnQiIFR5cGVOYW1lPSJ0bnM6"
"U2VydmljZUNvdW50ZXJEYXRhVHlwZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkJyb3dzZU5l"
"eHRDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFUeXBlIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iVHJhbnNsYXRlQnJvd3NlUGF0aHNUb05vZGVJZHNDb3VudCIgVHlwZU5h"
"bWU9InRuczpTZXJ2aWNlQ291bnRlckRhdGFUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"UXVlcnlGaXJzdENvdW50IiBUeXBlTmFtZT0idG5zOlNlcnZpY2VDb3VudGVyRGF0YVR5cGUiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJRdWVyeU5leHRDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2"
"aWNlQ291bnRlckRhdGFUeXBlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iUmVnaXN0ZXJOb2Rl"
"c0NvdW50IiBUeXBlTmFtZT0idG5zOlNlcnZpY2VDb3VudGVyRGF0YVR5cGUiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJVbnJlZ2lzdGVyTm9kZXNDb3VudCIgVHlwZU5hbWU9InRuczpTZXJ2aWNl"
"Q291bnRlckRhdGFUeXBlIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IlNlc3Npb25TZWN1cml0eURpYWdub3N0aWNzRGF0YVR5cGUiIEJh"
"c2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vzc2lv";
    memcpy(xmlValue.data + 218877, buf_45, 4864);
    char *buf_46 = "bklkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQ2xpZW50"
"VXNlcklkT2ZTZXNzaW9uIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9Ik5vT2ZDbGllbnRVc2VySWRIaXN0b3J5IiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iQ2xpZW50VXNlcklkSGlzdG9yeSIgVHlwZU5hbWU9Im9wYzpT"
"dHJpbmciIExlbmd0aEZpZWxkPSJOb09mQ2xpZW50VXNlcklkSGlzdG9yeSIgLz4NCiAgICA8b3Bj"
"OkZpZWxkIE5hbWU9IkF1dGhlbnRpY2F0aW9uTWVjaGFuaXNtIiBUeXBlTmFtZT0ib3BjOlN0cmlu"
"ZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuY29kaW5nIiBUeXBlTmFtZT0ib3BjOlN0cmlu"
"ZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlRyYW5zcG9ydFByb3RvY29sIiBUeXBlTmFtZT0i"
"b3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlY3VyaXR5TW9kZSIgVHlwZU5h"
"bWU9InRuczpNZXNzYWdlU2VjdXJpdHlNb2RlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iU2Vj"
"dXJpdHlQb2xpY3lVcmkiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iQ2xpZW50Q2VydGlmaWNhdGUiIFR5cGVOYW1lPSJvcGM6Qnl0ZVN0cmluZyIgLz4NCiAg"
"PC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTZXJ2"
"aWNlQ291bnRlckRhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8"
"b3BjOkZpZWxkIE5hbWU9IlRvdGFsQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iRXJyb3JDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQog"
"IDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iU3Rh"
"dHVzUmVzdWx0IiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IlN0YXR1c0NvZGUiIFR5cGVOYW1lPSJ1YTpTdGF0dXNDb2RlIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iRGlhZ25vc3RpY0luZm8iIFR5cGVOYW1lPSJ1YTpEaWFnbm9zdGljSW5mbyIg"
"Lz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1l"
"PSJTdWJzY3JpcHRpb25EaWFnbm9zdGljc0RhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9u"
"T2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlNlc3Npb25JZCIgVHlwZU5hbWU9InVhOk5v"
"ZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlN1YnNjcmlwdGlvbklkIiBUeXBlTmFtZT0i"
"b3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlByaW9yaXR5IiBUeXBlTmFtZT0i"
"b3BjOkJ5dGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQdWJsaXNoaW5nSW50ZXJ2YWwiIFR5"
"cGVOYW1lPSJvcGM6RG91YmxlIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWF4S2VlcEFsaXZl"
"Q291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWF4"
"TGlmZXRpbWVDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBO"
"YW1lPSJNYXhOb3RpZmljYXRpb25zUGVyUHVibGlzaCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+"
"DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQdWJsaXNoaW5nRW5hYmxlZCIgVHlwZU5hbWU9Im9wYzpC"
"b29sZWFuIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTW9kaWZ5Q291bnQiIFR5cGVOYW1lPSJv"
"cGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRW5hYmxlQ291bnQiIFR5cGVOYW1l"
"PSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iRGlzYWJsZUNvdW50IiBUeXBl"
"TmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlJlcHVibGlzaFJlcXVl"
"c3RDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJS"
"ZXB1Ymxpc2hNZXNzYWdlUmVxdWVzdENvdW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAg"
"ICA8b3BjOkZpZWxkIE5hbWU9IlJlcHVibGlzaE1lc3NhZ2VDb3VudCIgVHlwZU5hbWU9Im9wYzpV"
"SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUcmFuc2ZlclJlcXVlc3RDb3VudCIgVHlw"
"ZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUcmFuc2ZlcnJlZFRv"
"QWx0Q2xpZW50Q291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iVHJhbnNmZXJyZWRUb1NhbWVDbGllbnRDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJQdWJsaXNoUmVxdWVzdENvdW50IiBUeXBlTmFtZT0i"
"b3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRhdGFDaGFuZ2VOb3RpZmljYXRp"
"b25zQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0i"
"RXZlbnROb3RpZmljYXRpb25zQ291bnQiIFR5cGVOYW1lPSJvcGM6VUludDMyIiAvPg0KICAgIDxv"
"cGM6RmllbGQgTmFtZT0iTm90aWZpY2F0aW9uc0NvdW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkxhdGVQdWJsaXNoUmVxdWVzdENvdW50IiBUeXBlTmFt"
"ZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkN1cnJlbnRLZWVwQWxpdmVD"
"b3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDdXJy"
"ZW50TGlmZXRpbWVDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJVbmFja25vd2xlZGdlZE1lc3NhZ2VDb3VudCIgVHlwZU5hbWU9Im9wYzpVSW50MzIi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNjYXJkZWRNZXNzYWdlQ291bnQiIFR5cGVOYW1l"
"PSJvcGM6VUludDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTW9uaXRvcmVkSXRlbUNvdW50"
"IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkRpc2FibGVk"
"TW9uaXRvcmVkSXRlbUNvdW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ik1vbml0b3JpbmdRdWV1ZU92ZXJmbG93Q291bnQiIFR5cGVOYW1lPSJvcGM6VUlu"
"dDMyIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTmV4dFNlcXVlbmNlTnVtYmVyIiBUeXBlTmFt"
"ZT0ib3BjOlVJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkV2ZW50UXVldWVPdmVyRmxv"
"d0NvdW50IiBUeXBlTmFtZT0ib3BjOlVJbnQzMiIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+"
"DQoNCiAgPG9wYzpFbnVtZXJhdGVkVHlwZSBOYW1lPSJNb2RlbENoYW5nZVN0cnVjdHVyZVZlcmJN"
"YXNrIiBMZW5ndGhJbkJpdHM9IjMyIj4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJO"
"b2RlQWRkZWQiIFZhbHVlPSIxIiAvPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9Ik5v"
"ZGVEZWxldGVkIiBWYWx1ZT0iMiIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJS";
    memcpy(xmlValue.data + 223741, buf_46, 4864);
    char *buf_47 = "ZWZlcmVuY2VBZGRlZCIgVmFsdWU9IjQiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFt"
"ZT0iUmVmZXJlbmNlRGVsZXRlZCIgVmFsdWU9IjgiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFs"
"dWUgTmFtZT0iRGF0YVR5cGVDaGFuZ2VkIiBWYWx1ZT0iMTYiIC8+DQogIDwvb3BjOkVudW1lcmF0"
"ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iTW9kZWxDaGFuZ2VTdHJ1Y3R1"
"cmVEYXRhVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJBZmZlY3RlZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZpZWxk"
"IE5hbWU9IkFmZmVjdGVkVHlwZSIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IlZlcmIiIFR5cGVOYW1lPSJvcGM6Qnl0ZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJl"
"ZFR5cGU+DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJTZW1hbnRpY0NoYW5nZVN0cnVj"
"dHVyZURhdGFUeXBlIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9IkFmZmVjdGVkIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6Rmll"
"bGQgTmFtZT0iQWZmZWN0ZWRUeXBlIiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICA8L29wYzpT"
"dHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlJhbmdlIiBCYXNl"
"VHlwZT0idWE6RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkxvdyIgVHlw"
"ZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJIaWdoIiBUeXBlTmFt"
"ZT0ib3BjOkRvdWJsZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpTdHJ1"
"Y3R1cmVkVHlwZSBOYW1lPSJFVUluZm9ybWF0aW9uIiBCYXNlVHlwZT0idWE6RXh0ZW5zaW9uT2Jq"
"ZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5hbWVzcGFjZVVyaSIgVHlwZU5hbWU9Im9wYzpT"
"dHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVbml0SWQiIFR5cGVOYW1lPSJvcGM6SW50"
"MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEaXNwbGF5TmFtZSIgVHlwZU5hbWU9InVhOkxv"
"Y2FsaXplZFRleHQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJEZXNjcmlwdGlvbiIgVHlwZU5h"
"bWU9InVhOkxvY2FsaXplZFRleHQiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQogIDxv"
"cGM6RW51bWVyYXRlZFR5cGUgTmFtZT0iQXhpc1NjYWxlRW51bWVyYXRpb24iIExlbmd0aEluQml0"
"cz0iMzIiPg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkxpbmVhciIgVmFsdWU9IjAi"
"IC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iTG9nIiBWYWx1ZT0iMSIgLz4NCiAg"
"ICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJMbiIgVmFsdWU9IjIiIC8+DQogIDwvb3BjOkVu"
"dW1lcmF0ZWRUeXBlPg0KDQogIDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQ29tcGxleE51bWJl"
"clR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0KICAgIDxvcGM6RmllbGQgTmFt"
"ZT0iUmVhbCIgVHlwZU5hbWU9Im9wYzpGbG9hdCIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Iklt"
"YWdpbmFyeSIgVHlwZU5hbWU9Im9wYzpGbG9hdCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+"
"DQoNCiAgPG9wYzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJEb3VibGVDb21wbGV4TnVtYmVyVHlwZSIg"
"QmFzZVR5cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJSZWFs"
"IiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkltYWdpbmFy"
"eSIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIC8+DQogIDwvb3BjOlN0cnVjdHVyZWRUeXBlPg0KDQog"
"IDxvcGM6U3RydWN0dXJlZFR5cGUgTmFtZT0iQXhpc0luZm9ybWF0aW9uIiBCYXNlVHlwZT0idWE6"
"RXh0ZW5zaW9uT2JqZWN0Ij4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVuZ2luZWVyaW5nVW5pdHMi"
"IFR5cGVOYW1lPSJ0bnM6RVVJbmZvcm1hdGlvbiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IkVV"
"UmFuZ2UiIFR5cGVOYW1lPSJ0bnM6UmFuZ2UiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJUaXRs"
"ZSIgVHlwZU5hbWU9InVhOkxvY2FsaXplZFRleHQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJB"
"eGlzU2NhbGVUeXBlIiBUeXBlTmFtZT0idG5zOkF4aXNTY2FsZUVudW1lcmF0aW9uIiAvPg0KICAg"
"IDxvcGM6RmllbGQgTmFtZT0iTm9PZkF4aXNTdGVwcyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9IkF4aXNTdGVwcyIgVHlwZU5hbWU9Im9wYzpEb3VibGUiIExl"
"bmd0aEZpZWxkPSJOb09mQXhpc1N0ZXBzIiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0K"
"ICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlhWVHlwZSIgQmFzZVR5cGU9InVhOkV4dGVuc2lv"
"bk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJYIiBUeXBlTmFtZT0ib3BjOkRvdWJsZSIg"
"Lz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9IlZhbHVlIiBUeXBlTmFtZT0ib3BjOkZsb2F0IiAvPg0K"
"ICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0cnVjdHVyZWRUeXBlIE5hbWU9IlBy"
"b2dyYW1EaWFnbm9zdGljRGF0YVR5cGUiIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmplY3QiPg0K"
"ICAgIDxvcGM6RmllbGQgTmFtZT0iQ3JlYXRlU2Vzc2lvbklkIiBUeXBlTmFtZT0idWE6Tm9kZUlk"
"IiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iQ3JlYXRlQ2xpZW50TmFtZSIgVHlwZU5hbWU9Im9w"
"YzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJJbnZvY2F0aW9uQ3JlYXRpb25UaW1l"
"IiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTGFzdFRy"
"YW5zaXRpb25UaW1lIiBUeXBlTmFtZT0ib3BjOkRhdGVUaW1lIiAvPg0KICAgIDxvcGM6RmllbGQg"
"TmFtZT0iTGFzdE1ldGhvZENhbGwiIFR5cGVOYW1lPSJvcGM6U3RyaW5nIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTGFzdE1ldGhvZFNlc3Npb25JZCIgVHlwZU5hbWU9InVhOk5vZGVJZCIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZMYXN0TWV0aG9kSW5wdXRBcmd1bWVudHMiIFR5cGVO"
"YW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJMYXN0TWV0aG9kSW5wdXRB"
"cmd1bWVudHMiIFR5cGVOYW1lPSJ0bnM6QXJndW1lbnQiIExlbmd0aEZpZWxkPSJOb09mTGFzdE1l"
"dGhvZElucHV0QXJndW1lbnRzIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkxhc3RNZXRo"
"b2RPdXRwdXRBcmd1bWVudHMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVs"
"ZCBOYW1lPSJMYXN0TWV0aG9kT3V0cHV0QXJndW1lbnRzIiBUeXBlTmFtZT0idG5zOkFyZ3VtZW50"
"IiBMZW5ndGhGaWVsZD0iTm9PZkxhc3RNZXRob2RPdXRwdXRBcmd1bWVudHMiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJMYXN0TWV0aG9kQ2FsbFRpbWUiIFR5cGVOYW1lPSJvcGM6RGF0ZVRpbWUi"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJMYXN0TWV0aG9kUmV0dXJuU3RhdHVzIiBUeXBlTmFt";
    memcpy(xmlValue.data + 228605, buf_47, 4864);
    char *buf_48 = "ZT0idG5zOlN0YXR1c1Jlc3VsdCIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9w"
"YzpTdHJ1Y3R1cmVkVHlwZSBOYW1lPSJQcm9ncmFtRGlhZ25vc3RpYzJEYXRhVHlwZSIgQmFzZVR5"
"cGU9InVhOkV4dGVuc2lvbk9iamVjdCI+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDcmVhdGVTZXNz"
"aW9uSWQiIFR5cGVOYW1lPSJ1YTpOb2RlSWQiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJDcmVh"
"dGVDbGllbnROYW1lIiBUeXBlTmFtZT0ib3BjOlN0cmluZyIgLz4NCiAgICA8b3BjOkZpZWxkIE5h"
"bWU9Ikludm9jYXRpb25DcmVhdGlvblRpbWUiIFR5cGVOYW1lPSJvcGM6RGF0ZVRpbWUiIC8+DQog"
"ICAgPG9wYzpGaWVsZCBOYW1lPSJMYXN0VHJhbnNpdGlvblRpbWUiIFR5cGVOYW1lPSJvcGM6RGF0"
"ZVRpbWUiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJMYXN0TWV0aG9kQ2FsbCIgVHlwZU5hbWU9"
"Im9wYzpTdHJpbmciIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJMYXN0TWV0aG9kU2Vzc2lvbklk"
"IiBUeXBlTmFtZT0idWE6Tm9kZUlkIiAvPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTm9PZkxhc3RN"
"ZXRob2RJbnB1dEFyZ3VtZW50cyIgVHlwZU5hbWU9Im9wYzpJbnQzMiIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ikxhc3RNZXRob2RJbnB1dEFyZ3VtZW50cyIgVHlwZU5hbWU9InRuczpBcmd1bWVu"
"dCIgTGVuZ3RoRmllbGQ9Ik5vT2ZMYXN0TWV0aG9kSW5wdXRBcmd1bWVudHMiIC8+DQogICAgPG9w"
"YzpGaWVsZCBOYW1lPSJOb09mTGFzdE1ldGhvZE91dHB1dEFyZ3VtZW50cyIgVHlwZU5hbWU9Im9w"
"YzpJbnQzMiIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ikxhc3RNZXRob2RPdXRwdXRBcmd1bWVu"
"dHMiIFR5cGVOYW1lPSJ0bnM6QXJndW1lbnQiIExlbmd0aEZpZWxkPSJOb09mTGFzdE1ldGhvZE91"
"dHB1dEFyZ3VtZW50cyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZMYXN0TWV0aG9kSW5w"
"dXRWYWx1ZXMiIFR5cGVOYW1lPSJvcGM6SW50MzIiIC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJM"
"YXN0TWV0aG9kSW5wdXRWYWx1ZXMiIFR5cGVOYW1lPSJ1YTpWYXJpYW50IiBMZW5ndGhGaWVsZD0i"
"Tm9PZkxhc3RNZXRob2RJbnB1dFZhbHVlcyIgLz4NCiAgICA8b3BjOkZpZWxkIE5hbWU9Ik5vT2ZM"
"YXN0TWV0aG9kT3V0cHV0VmFsdWVzIiBUeXBlTmFtZT0ib3BjOkludDMyIiAvPg0KICAgIDxvcGM6"
"RmllbGQgTmFtZT0iTGFzdE1ldGhvZE91dHB1dFZhbHVlcyIgVHlwZU5hbWU9InVhOlZhcmlhbnQi"
"IExlbmd0aEZpZWxkPSJOb09mTGFzdE1ldGhvZE91dHB1dFZhbHVlcyIgLz4NCiAgICA8b3BjOkZp"
"ZWxkIE5hbWU9Ikxhc3RNZXRob2RDYWxsVGltZSIgVHlwZU5hbWU9Im9wYzpEYXRlVGltZSIgLz4N"
"CiAgICA8b3BjOkZpZWxkIE5hbWU9Ikxhc3RNZXRob2RSZXR1cm5TdGF0dXMiIFR5cGVOYW1lPSJ0"
"bnM6U3RhdHVzUmVzdWx0IiAvPg0KICA8L29wYzpTdHJ1Y3R1cmVkVHlwZT4NCg0KICA8b3BjOlN0"
"cnVjdHVyZWRUeXBlIE5hbWU9IkFubm90YXRpb24iIEJhc2VUeXBlPSJ1YTpFeHRlbnNpb25PYmpl"
"Y3QiPg0KICAgIDxvcGM6RmllbGQgTmFtZT0iTWVzc2FnZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmci"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJVc2VyTmFtZSIgVHlwZU5hbWU9Im9wYzpTdHJpbmci"
"IC8+DQogICAgPG9wYzpGaWVsZCBOYW1lPSJBbm5vdGF0aW9uVGltZSIgVHlwZU5hbWU9Im9wYzpE"
"YXRlVGltZSIgLz4NCiAgPC9vcGM6U3RydWN0dXJlZFR5cGU+DQoNCiAgPG9wYzpFbnVtZXJhdGVk"
"VHlwZSBOYW1lPSJFeGNlcHRpb25EZXZpYXRpb25Gb3JtYXQiIExlbmd0aEluQml0cz0iMzIiPg0K"
"ICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IkFic29sdXRlVmFsdWUiIFZhbHVlPSIwIiAv"
"Pg0KICAgIDxvcGM6RW51bWVyYXRlZFZhbHVlIE5hbWU9IlBlcmNlbnRPZlZhbHVlIiBWYWx1ZT0i"
"MSIgLz4NCiAgICA8b3BjOkVudW1lcmF0ZWRWYWx1ZSBOYW1lPSJQZXJjZW50T2ZSYW5nZSIgVmFs"
"dWU9IjIiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iUGVyY2VudE9mRVVSYW5n"
"ZSIgVmFsdWU9IjMiIC8+DQogICAgPG9wYzpFbnVtZXJhdGVkVmFsdWUgTmFtZT0iVW5rbm93biIg"
"VmFsdWU9IjQiIC8+DQogIDwvb3BjOkVudW1lcmF0ZWRUeXBlPg0KDQo8L29wYzpUeXBlRGljdGlv"
"bmFyeT4=</ByteString>"
    "</Value>";
    memcpy(xmlValue.data + 233469, buf_48, 2917);
}
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "Opc.Ua");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7617LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 93LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Opc.Ua"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 72LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_String_clear(&xmlValue);
#endif /* UA_ENABLE_XML_ENCODING */
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
return retVal;
}

static UA_StatusCode function_namespace0_generated_825_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7617LU));
}

/* NamespaceUri - ns=0;i=107 */

static UA_StatusCode function_namespace0_generated_826_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceUri");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A URI that uniquely identifies the dictionary.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 107LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 72LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "NamespaceUri"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 107LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_826_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 107LU));
}

/* DataTypeVersion - ns=0;i=106 */

static UA_StatusCode function_namespace0_generated_827_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 106LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 72LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataTypeVersion"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 106LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_827_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 106LU));
}

/* DataTypeDescriptionType - ns=0;i=69 */

static UA_StatusCode function_namespace0_generated_828_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDescriptionType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 69LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 63LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 45LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataTypeDescriptionType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_828_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 69LU));
}

/* EnumValueType - ns=0;i=7656 */

static UA_StatusCode function_namespace0_generated_829_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<String xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">EnumValueType</String>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7656LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7617LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "EnumValueType"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 69LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7656LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 39LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 8251LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_829_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7656LU));
}

/* Argument - ns=0;i=7650 */

static UA_StatusCode function_namespace0_generated_830_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
#ifdef UA_ENABLE_XML_ENCODING
UA_String xmlValue = UA_STRING("<Value>"
      "<String xmlns=\"http://opcfoundation.org/UA/2008/02/Types.xsd\">Argument</String>"
    "</Value>");
UA_DecodeXmlOptions opts;
memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
opts.unwrapped = true;
opts.namespaceMapping = nsMapping;
opts.customTypes = UA_Server_getConfig(server)->customDataTypes;
retVal |= UA_decodeXml(&xmlValue, &attr.value, &UA_TYPES[UA_TYPES_VARIANT], &opts);
#endif /* UA_ENABLE_XML_ENCODING */
attr.displayName = UA_LOCALIZEDTEXT("", "Argument");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7650LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7617LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 47LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Argument"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 69LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
#ifdef UA_ENABLE_XML_ENCODING
UA_Variant_clear(&attr.value);
#endif /* UA_ENABLE_XML_ENCODING */
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7650LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 39LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 298LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_830_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 7650LU));
}

/* DictionaryFragment - ns=0;i=105 */

static UA_StatusCode function_namespace0_generated_831_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DictionaryFragment");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 105LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 69LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DictionaryFragment"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 105LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_831_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 105LU));
}

/* DataTypeVersion - ns=0;i=104 */

static UA_StatusCode function_namespace0_generated_832_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 104LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 69LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 46LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "DataTypeVersion"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 104LU), UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 37LU), UA_EXPANDEDNODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_832_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 104LU));
}

/* Default XML - ns=0;i=3063 */

static UA_StatusCode function_namespace0_generated_833_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default XML");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3063LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Default XML"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_833_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3063LU));
}

/* Default Binary - ns=0;i=3062 */

static UA_StatusCode function_namespace0_generated_834_begin(UA_Server *server, UA_NamespaceMapping *nsMapping) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3062LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 0LU),UA_QUALIFIEDNAME(UA_NamespaceMapping_local2Remote(nsMapping, 0), "Default Binary"),UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 58LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_834_finish(UA_Server *server, UA_NamespaceMapping *nsMapping) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(UA_NamespaceMapping_local2Remote(nsMapping, 0), 3062LU));
}

UA_StatusCode namespace0_generated(UA_Server *server) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
/* Use namespace ids generated by the server */
UA_UInt16 ns[2];
ns[0] = UA_Server_addNamespace(server, "http://opcfoundation.org/UA/");
UA_UInt16 nsMappingTable[2] = {ns[0], ns[1]};
UA_NamespaceMapping nsMapping;
memset(&nsMapping, 0, sizeof(UA_NamespaceMapping));
nsMapping.local2remote = ns;
nsMapping.local2remoteSize = 1;
nsMapping.remote2local = nsMappingTable;
nsMapping.remote2localSize = 2;

/* Load custom datatype definitions into the server */
retVal |= function_namespace0_generated_0_begin(server, &nsMapping);
retVal |= function_namespace0_generated_0_finish(server, &nsMapping);
retVal |= function_namespace0_generated_1_begin(server, &nsMapping);
retVal |= function_namespace0_generated_1_finish(server, &nsMapping);
retVal |= function_namespace0_generated_2_begin(server, &nsMapping);
retVal |= function_namespace0_generated_2_finish(server, &nsMapping);
retVal |= function_namespace0_generated_3_begin(server, &nsMapping);
retVal |= function_namespace0_generated_3_finish(server, &nsMapping);
retVal |= function_namespace0_generated_4_begin(server, &nsMapping);
retVal |= function_namespace0_generated_4_finish(server, &nsMapping);
retVal |= function_namespace0_generated_5_begin(server, &nsMapping);
retVal |= function_namespace0_generated_5_finish(server, &nsMapping);
retVal |= function_namespace0_generated_6_begin(server, &nsMapping);
retVal |= function_namespace0_generated_6_finish(server, &nsMapping);
retVal |= function_namespace0_generated_7_begin(server, &nsMapping);
retVal |= function_namespace0_generated_7_finish(server, &nsMapping);
retVal |= function_namespace0_generated_8_begin(server, &nsMapping);
retVal |= function_namespace0_generated_8_finish(server, &nsMapping);
retVal |= function_namespace0_generated_9_begin(server, &nsMapping);
retVal |= function_namespace0_generated_9_finish(server, &nsMapping);
retVal |= function_namespace0_generated_10_begin(server, &nsMapping);
retVal |= function_namespace0_generated_10_finish(server, &nsMapping);
retVal |= function_namespace0_generated_11_begin(server, &nsMapping);
retVal |= function_namespace0_generated_12_begin(server, &nsMapping);
retVal |= function_namespace0_generated_13_begin(server, &nsMapping);
retVal |= function_namespace0_generated_14_begin(server, &nsMapping);
retVal |= function_namespace0_generated_15_begin(server, &nsMapping);
retVal |= function_namespace0_generated_16_begin(server, &nsMapping);
retVal |= function_namespace0_generated_17_begin(server, &nsMapping);
retVal |= function_namespace0_generated_18_begin(server, &nsMapping);
retVal |= function_namespace0_generated_19_begin(server, &nsMapping);
retVal |= function_namespace0_generated_20_begin(server, &nsMapping);
retVal |= function_namespace0_generated_21_begin(server, &nsMapping);
retVal |= function_namespace0_generated_22_begin(server, &nsMapping);
retVal |= function_namespace0_generated_23_begin(server, &nsMapping);
retVal |= function_namespace0_generated_24_begin(server, &nsMapping);
retVal |= function_namespace0_generated_25_begin(server, &nsMapping);
retVal |= function_namespace0_generated_26_begin(server, &nsMapping);
retVal |= function_namespace0_generated_27_begin(server, &nsMapping);
retVal |= function_namespace0_generated_28_begin(server, &nsMapping);
retVal |= function_namespace0_generated_29_begin(server, &nsMapping);
retVal |= function_namespace0_generated_30_begin(server, &nsMapping);
retVal |= function_namespace0_generated_31_begin(server, &nsMapping);
retVal |= function_namespace0_generated_32_begin(server, &nsMapping);
retVal |= function_namespace0_generated_33_begin(server, &nsMapping);
retVal |= function_namespace0_generated_34_begin(server, &nsMapping);
retVal |= function_namespace0_generated_35_begin(server, &nsMapping);
retVal |= function_namespace0_generated_36_begin(server, &nsMapping);
retVal |= function_namespace0_generated_37_begin(server, &nsMapping);
retVal |= function_namespace0_generated_38_begin(server, &nsMapping);
retVal |= function_namespace0_generated_39_begin(server, &nsMapping);
retVal |= function_namespace0_generated_40_begin(server, &nsMapping);
retVal |= function_namespace0_generated_41_begin(server, &nsMapping);
retVal |= function_namespace0_generated_42_begin(server, &nsMapping);
retVal |= function_namespace0_generated_43_begin(server, &nsMapping);
retVal |= function_namespace0_generated_44_begin(server, &nsMapping);
retVal |= function_namespace0_generated_45_begin(server, &nsMapping);
retVal |= function_namespace0_generated_46_begin(server, &nsMapping);
retVal |= function_namespace0_generated_47_begin(server, &nsMapping);
retVal |= function_namespace0_generated_48_begin(server, &nsMapping);
retVal |= function_namespace0_generated_49_begin(server, &nsMapping);
retVal |= function_namespace0_generated_50_begin(server, &nsMapping);
retVal |= function_namespace0_generated_51_begin(server, &nsMapping);
retVal |= function_namespace0_generated_52_begin(server, &nsMapping);
retVal |= function_namespace0_generated_53_begin(server, &nsMapping);
retVal |= function_namespace0_generated_54_begin(server, &nsMapping);
retVal |= function_namespace0_generated_55_begin(server, &nsMapping);
retVal |= function_namespace0_generated_56_begin(server, &nsMapping);
retVal |= function_namespace0_generated_57_begin(server, &nsMapping);
retVal |= function_namespace0_generated_58_begin(server, &nsMapping);
retVal |= function_namespace0_generated_59_begin(server, &nsMapping);
retVal |= function_namespace0_generated_60_begin(server, &nsMapping);
retVal |= function_namespace0_generated_61_begin(server, &nsMapping);
retVal |= function_namespace0_generated_62_begin(server, &nsMapping);
retVal |= function_namespace0_generated_63_begin(server, &nsMapping);
retVal |= function_namespace0_generated_64_begin(server, &nsMapping);
retVal |= function_namespace0_generated_65_begin(server, &nsMapping);
retVal |= function_namespace0_generated_66_begin(server, &nsMapping);
retVal |= function_namespace0_generated_67_begin(server, &nsMapping);
retVal |= function_namespace0_generated_68_begin(server, &nsMapping);
retVal |= function_namespace0_generated_69_begin(server, &nsMapping);
retVal |= function_namespace0_generated_70_begin(server, &nsMapping);
retVal |= function_namespace0_generated_71_begin(server, &nsMapping);
retVal |= function_namespace0_generated_72_begin(server, &nsMapping);
retVal |= function_namespace0_generated_73_begin(server, &nsMapping);
retVal |= function_namespace0_generated_74_begin(server, &nsMapping);
retVal |= function_namespace0_generated_75_begin(server, &nsMapping);
retVal |= function_namespace0_generated_76_begin(server, &nsMapping);
retVal |= function_namespace0_generated_77_begin(server, &nsMapping);
retVal |= function_namespace0_generated_78_begin(server, &nsMapping);
retVal |= function_namespace0_generated_79_begin(server, &nsMapping);
retVal |= function_namespace0_generated_80_begin(server, &nsMapping);
retVal |= function_namespace0_generated_81_begin(server, &nsMapping);
retVal |= function_namespace0_generated_82_begin(server, &nsMapping);
retVal |= function_namespace0_generated_83_begin(server, &nsMapping);
retVal |= function_namespace0_generated_84_begin(server, &nsMapping);
retVal |= function_namespace0_generated_85_begin(server, &nsMapping);
retVal |= function_namespace0_generated_86_begin(server, &nsMapping);
retVal |= function_namespace0_generated_87_begin(server, &nsMapping);
retVal |= function_namespace0_generated_88_begin(server, &nsMapping);
retVal |= function_namespace0_generated_89_begin(server, &nsMapping);
retVal |= function_namespace0_generated_90_begin(server, &nsMapping);
retVal |= function_namespace0_generated_91_begin(server, &nsMapping);
retVal |= function_namespace0_generated_92_begin(server, &nsMapping);
retVal |= function_namespace0_generated_93_begin(server, &nsMapping);
retVal |= function_namespace0_generated_94_begin(server, &nsMapping);
retVal |= function_namespace0_generated_95_begin(server, &nsMapping);
retVal |= function_namespace0_generated_96_begin(server, &nsMapping);
retVal |= function_namespace0_generated_97_begin(server, &nsMapping);
retVal |= function_namespace0_generated_98_begin(server, &nsMapping);
retVal |= function_namespace0_generated_99_begin(server, &nsMapping);
retVal |= function_namespace0_generated_100_begin(server, &nsMapping);
retVal |= function_namespace0_generated_101_begin(server, &nsMapping);
retVal |= function_namespace0_generated_102_begin(server, &nsMapping);
retVal |= function_namespace0_generated_103_begin(server, &nsMapping);
retVal |= function_namespace0_generated_104_begin(server, &nsMapping);
retVal |= function_namespace0_generated_105_begin(server, &nsMapping);
retVal |= function_namespace0_generated_106_begin(server, &nsMapping);
retVal |= function_namespace0_generated_107_begin(server, &nsMapping);
retVal |= function_namespace0_generated_108_begin(server, &nsMapping);
retVal |= function_namespace0_generated_109_begin(server, &nsMapping);
retVal |= function_namespace0_generated_110_begin(server, &nsMapping);
retVal |= function_namespace0_generated_111_begin(server, &nsMapping);
retVal |= function_namespace0_generated_112_begin(server, &nsMapping);
retVal |= function_namespace0_generated_113_begin(server, &nsMapping);
retVal |= function_namespace0_generated_114_begin(server, &nsMapping);
retVal |= function_namespace0_generated_115_begin(server, &nsMapping);
retVal |= function_namespace0_generated_116_begin(server, &nsMapping);
retVal |= function_namespace0_generated_117_begin(server, &nsMapping);
retVal |= function_namespace0_generated_118_begin(server, &nsMapping);
retVal |= function_namespace0_generated_119_begin(server, &nsMapping);
retVal |= function_namespace0_generated_120_begin(server, &nsMapping);
retVal |= function_namespace0_generated_121_begin(server, &nsMapping);
retVal |= function_namespace0_generated_122_begin(server, &nsMapping);
retVal |= function_namespace0_generated_123_begin(server, &nsMapping);
retVal |= function_namespace0_generated_124_begin(server, &nsMapping);
retVal |= function_namespace0_generated_125_begin(server, &nsMapping);
retVal |= function_namespace0_generated_126_begin(server, &nsMapping);
retVal |= function_namespace0_generated_127_begin(server, &nsMapping);
retVal |= function_namespace0_generated_128_begin(server, &nsMapping);
retVal |= function_namespace0_generated_129_begin(server, &nsMapping);
retVal |= function_namespace0_generated_130_begin(server, &nsMapping);
retVal |= function_namespace0_generated_131_begin(server, &nsMapping);
retVal |= function_namespace0_generated_132_begin(server, &nsMapping);
retVal |= function_namespace0_generated_133_begin(server, &nsMapping);
retVal |= function_namespace0_generated_134_begin(server, &nsMapping);
retVal |= function_namespace0_generated_135_begin(server, &nsMapping);
retVal |= function_namespace0_generated_136_begin(server, &nsMapping);
retVal |= function_namespace0_generated_137_begin(server, &nsMapping);
retVal |= function_namespace0_generated_138_begin(server, &nsMapping);
retVal |= function_namespace0_generated_139_begin(server, &nsMapping);
retVal |= function_namespace0_generated_140_begin(server, &nsMapping);
retVal |= function_namespace0_generated_141_begin(server, &nsMapping);
retVal |= function_namespace0_generated_142_begin(server, &nsMapping);
retVal |= function_namespace0_generated_143_begin(server, &nsMapping);
retVal |= function_namespace0_generated_144_begin(server, &nsMapping);
retVal |= function_namespace0_generated_145_begin(server, &nsMapping);
retVal |= function_namespace0_generated_146_begin(server, &nsMapping);
retVal |= function_namespace0_generated_147_begin(server, &nsMapping);
retVal |= function_namespace0_generated_148_begin(server, &nsMapping);
retVal |= function_namespace0_generated_149_begin(server, &nsMapping);
retVal |= function_namespace0_generated_150_begin(server, &nsMapping);
retVal |= function_namespace0_generated_151_begin(server, &nsMapping);
retVal |= function_namespace0_generated_152_begin(server, &nsMapping);
retVal |= function_namespace0_generated_153_begin(server, &nsMapping);
retVal |= function_namespace0_generated_154_begin(server, &nsMapping);
retVal |= function_namespace0_generated_155_begin(server, &nsMapping);
retVal |= function_namespace0_generated_156_begin(server, &nsMapping);
retVal |= function_namespace0_generated_157_begin(server, &nsMapping);
retVal |= function_namespace0_generated_158_begin(server, &nsMapping);
retVal |= function_namespace0_generated_159_begin(server, &nsMapping);
retVal |= function_namespace0_generated_160_begin(server, &nsMapping);
retVal |= function_namespace0_generated_161_begin(server, &nsMapping);
retVal |= function_namespace0_generated_162_begin(server, &nsMapping);
retVal |= function_namespace0_generated_163_begin(server, &nsMapping);
retVal |= function_namespace0_generated_164_begin(server, &nsMapping);
retVal |= function_namespace0_generated_165_begin(server, &nsMapping);
retVal |= function_namespace0_generated_166_begin(server, &nsMapping);
retVal |= function_namespace0_generated_167_begin(server, &nsMapping);
retVal |= function_namespace0_generated_168_begin(server, &nsMapping);
retVal |= function_namespace0_generated_169_begin(server, &nsMapping);
retVal |= function_namespace0_generated_170_begin(server, &nsMapping);
retVal |= function_namespace0_generated_171_begin(server, &nsMapping);
retVal |= function_namespace0_generated_172_begin(server, &nsMapping);
retVal |= function_namespace0_generated_173_begin(server, &nsMapping);
retVal |= function_namespace0_generated_174_begin(server, &nsMapping);
retVal |= function_namespace0_generated_175_begin(server, &nsMapping);
retVal |= function_namespace0_generated_176_begin(server, &nsMapping);
retVal |= function_namespace0_generated_177_begin(server, &nsMapping);
retVal |= function_namespace0_generated_178_begin(server, &nsMapping);
retVal |= function_namespace0_generated_179_begin(server, &nsMapping);
retVal |= function_namespace0_generated_180_begin(server, &nsMapping);
retVal |= function_namespace0_generated_181_begin(server, &nsMapping);
retVal |= function_namespace0_generated_182_begin(server, &nsMapping);
retVal |= function_namespace0_generated_183_begin(server, &nsMapping);
retVal |= function_namespace0_generated_184_begin(server, &nsMapping);
retVal |= function_namespace0_generated_185_begin(server, &nsMapping);
retVal |= function_namespace0_generated_186_begin(server, &nsMapping);
retVal |= function_namespace0_generated_187_begin(server, &nsMapping);
retVal |= function_namespace0_generated_188_begin(server, &nsMapping);
retVal |= function_namespace0_generated_189_begin(server, &nsMapping);
retVal |= function_namespace0_generated_190_begin(server, &nsMapping);
retVal |= function_namespace0_generated_191_begin(server, &nsMapping);
retVal |= function_namespace0_generated_192_begin(server, &nsMapping);
retVal |= function_namespace0_generated_193_begin(server, &nsMapping);
retVal |= function_namespace0_generated_194_begin(server, &nsMapping);
retVal |= function_namespace0_generated_195_begin(server, &nsMapping);
retVal |= function_namespace0_generated_196_begin(server, &nsMapping);
retVal |= function_namespace0_generated_197_begin(server, &nsMapping);
retVal |= function_namespace0_generated_198_begin(server, &nsMapping);
retVal |= function_namespace0_generated_199_begin(server, &nsMapping);
retVal |= function_namespace0_generated_200_begin(server, &nsMapping);
retVal |= function_namespace0_generated_201_begin(server, &nsMapping);
retVal |= function_namespace0_generated_202_begin(server, &nsMapping);
retVal |= function_namespace0_generated_203_begin(server, &nsMapping);
retVal |= function_namespace0_generated_204_begin(server, &nsMapping);
retVal |= function_namespace0_generated_205_begin(server, &nsMapping);
retVal |= function_namespace0_generated_206_begin(server, &nsMapping);
retVal |= function_namespace0_generated_207_begin(server, &nsMapping);
retVal |= function_namespace0_generated_208_begin(server, &nsMapping);
retVal |= function_namespace0_generated_209_begin(server, &nsMapping);
retVal |= function_namespace0_generated_210_begin(server, &nsMapping);
retVal |= function_namespace0_generated_211_begin(server, &nsMapping);
retVal |= function_namespace0_generated_212_begin(server, &nsMapping);
retVal |= function_namespace0_generated_213_begin(server, &nsMapping);
retVal |= function_namespace0_generated_214_begin(server, &nsMapping);
retVal |= function_namespace0_generated_215_begin(server, &nsMapping);
retVal |= function_namespace0_generated_216_begin(server, &nsMapping);
retVal |= function_namespace0_generated_217_begin(server, &nsMapping);
retVal |= function_namespace0_generated_218_begin(server, &nsMapping);
retVal |= function_namespace0_generated_219_begin(server, &nsMapping);
retVal |= function_namespace0_generated_220_begin(server, &nsMapping);
retVal |= function_namespace0_generated_221_begin(server, &nsMapping);
retVal |= function_namespace0_generated_222_begin(server, &nsMapping);
retVal |= function_namespace0_generated_223_begin(server, &nsMapping);
retVal |= function_namespace0_generated_224_begin(server, &nsMapping);
retVal |= function_namespace0_generated_225_begin(server, &nsMapping);
retVal |= function_namespace0_generated_226_begin(server, &nsMapping);
retVal |= function_namespace0_generated_227_begin(server, &nsMapping);
retVal |= function_namespace0_generated_228_begin(server, &nsMapping);
retVal |= function_namespace0_generated_229_begin(server, &nsMapping);
retVal |= function_namespace0_generated_230_begin(server, &nsMapping);
retVal |= function_namespace0_generated_231_begin(server, &nsMapping);
retVal |= function_namespace0_generated_232_begin(server, &nsMapping);
retVal |= function_namespace0_generated_233_begin(server, &nsMapping);
retVal |= function_namespace0_generated_234_begin(server, &nsMapping);
retVal |= function_namespace0_generated_235_begin(server, &nsMapping);
retVal |= function_namespace0_generated_236_begin(server, &nsMapping);
retVal |= function_namespace0_generated_237_begin(server, &nsMapping);
retVal |= function_namespace0_generated_238_begin(server, &nsMapping);
retVal |= function_namespace0_generated_239_begin(server, &nsMapping);
retVal |= function_namespace0_generated_240_begin(server, &nsMapping);
retVal |= function_namespace0_generated_241_begin(server, &nsMapping);
retVal |= function_namespace0_generated_242_begin(server, &nsMapping);
retVal |= function_namespace0_generated_243_begin(server, &nsMapping);
retVal |= function_namespace0_generated_244_begin(server, &nsMapping);
retVal |= function_namespace0_generated_245_begin(server, &nsMapping);
retVal |= function_namespace0_generated_246_begin(server, &nsMapping);
retVal |= function_namespace0_generated_247_begin(server, &nsMapping);
retVal |= function_namespace0_generated_248_begin(server, &nsMapping);
retVal |= function_namespace0_generated_249_begin(server, &nsMapping);
retVal |= function_namespace0_generated_250_begin(server, &nsMapping);
retVal |= function_namespace0_generated_251_begin(server, &nsMapping);
retVal |= function_namespace0_generated_252_begin(server, &nsMapping);
retVal |= function_namespace0_generated_253_begin(server, &nsMapping);
retVal |= function_namespace0_generated_254_begin(server, &nsMapping);
retVal |= function_namespace0_generated_255_begin(server, &nsMapping);
retVal |= function_namespace0_generated_256_begin(server, &nsMapping);
retVal |= function_namespace0_generated_257_begin(server, &nsMapping);
retVal |= function_namespace0_generated_258_begin(server, &nsMapping);
retVal |= function_namespace0_generated_259_begin(server, &nsMapping);
retVal |= function_namespace0_generated_260_begin(server, &nsMapping);
retVal |= function_namespace0_generated_261_begin(server, &nsMapping);
retVal |= function_namespace0_generated_262_begin(server, &nsMapping);
retVal |= function_namespace0_generated_263_begin(server, &nsMapping);
retVal |= function_namespace0_generated_264_begin(server, &nsMapping);
retVal |= function_namespace0_generated_265_begin(server, &nsMapping);
retVal |= function_namespace0_generated_266_begin(server, &nsMapping);
retVal |= function_namespace0_generated_267_begin(server, &nsMapping);
retVal |= function_namespace0_generated_268_begin(server, &nsMapping);
retVal |= function_namespace0_generated_269_begin(server, &nsMapping);
retVal |= function_namespace0_generated_270_begin(server, &nsMapping);
retVal |= function_namespace0_generated_271_begin(server, &nsMapping);
retVal |= function_namespace0_generated_272_begin(server, &nsMapping);
retVal |= function_namespace0_generated_273_begin(server, &nsMapping);
retVal |= function_namespace0_generated_274_begin(server, &nsMapping);
retVal |= function_namespace0_generated_275_begin(server, &nsMapping);
retVal |= function_namespace0_generated_276_begin(server, &nsMapping);
retVal |= function_namespace0_generated_277_begin(server, &nsMapping);
retVal |= function_namespace0_generated_278_begin(server, &nsMapping);
retVal |= function_namespace0_generated_279_begin(server, &nsMapping);
retVal |= function_namespace0_generated_280_begin(server, &nsMapping);
retVal |= function_namespace0_generated_281_begin(server, &nsMapping);
retVal |= function_namespace0_generated_282_begin(server, &nsMapping);
retVal |= function_namespace0_generated_283_begin(server, &nsMapping);
retVal |= function_namespace0_generated_284_begin(server, &nsMapping);
retVal |= function_namespace0_generated_285_begin(server, &nsMapping);
retVal |= function_namespace0_generated_286_begin(server, &nsMapping);
retVal |= function_namespace0_generated_287_begin(server, &nsMapping);
retVal |= function_namespace0_generated_288_begin(server, &nsMapping);
retVal |= function_namespace0_generated_289_begin(server, &nsMapping);
retVal |= function_namespace0_generated_290_begin(server, &nsMapping);
retVal |= function_namespace0_generated_291_begin(server, &nsMapping);
retVal |= function_namespace0_generated_292_begin(server, &nsMapping);
retVal |= function_namespace0_generated_293_begin(server, &nsMapping);
retVal |= function_namespace0_generated_294_begin(server, &nsMapping);
retVal |= function_namespace0_generated_295_begin(server, &nsMapping);
retVal |= function_namespace0_generated_296_begin(server, &nsMapping);
retVal |= function_namespace0_generated_297_begin(server, &nsMapping);
retVal |= function_namespace0_generated_298_begin(server, &nsMapping);
retVal |= function_namespace0_generated_299_begin(server, &nsMapping);
retVal |= function_namespace0_generated_300_begin(server, &nsMapping);
retVal |= function_namespace0_generated_301_begin(server, &nsMapping);
retVal |= function_namespace0_generated_302_begin(server, &nsMapping);
retVal |= function_namespace0_generated_303_begin(server, &nsMapping);
retVal |= function_namespace0_generated_304_begin(server, &nsMapping);
retVal |= function_namespace0_generated_305_begin(server, &nsMapping);
retVal |= function_namespace0_generated_306_begin(server, &nsMapping);
retVal |= function_namespace0_generated_307_begin(server, &nsMapping);
retVal |= function_namespace0_generated_308_begin(server, &nsMapping);
retVal |= function_namespace0_generated_309_begin(server, &nsMapping);
retVal |= function_namespace0_generated_310_begin(server, &nsMapping);
retVal |= function_namespace0_generated_311_begin(server, &nsMapping);
retVal |= function_namespace0_generated_312_begin(server, &nsMapping);
retVal |= function_namespace0_generated_313_begin(server, &nsMapping);
retVal |= function_namespace0_generated_314_begin(server, &nsMapping);
retVal |= function_namespace0_generated_315_begin(server, &nsMapping);
retVal |= function_namespace0_generated_316_begin(server, &nsMapping);
retVal |= function_namespace0_generated_317_begin(server, &nsMapping);
retVal |= function_namespace0_generated_318_begin(server, &nsMapping);
retVal |= function_namespace0_generated_319_begin(server, &nsMapping);
retVal |= function_namespace0_generated_320_begin(server, &nsMapping);
retVal |= function_namespace0_generated_321_begin(server, &nsMapping);
retVal |= function_namespace0_generated_322_begin(server, &nsMapping);
retVal |= function_namespace0_generated_323_begin(server, &nsMapping);
retVal |= function_namespace0_generated_324_begin(server, &nsMapping);
retVal |= function_namespace0_generated_325_begin(server, &nsMapping);
retVal |= function_namespace0_generated_326_begin(server, &nsMapping);
retVal |= function_namespace0_generated_327_begin(server, &nsMapping);
retVal |= function_namespace0_generated_328_begin(server, &nsMapping);
retVal |= function_namespace0_generated_329_begin(server, &nsMapping);
retVal |= function_namespace0_generated_330_begin(server, &nsMapping);
retVal |= function_namespace0_generated_331_begin(server, &nsMapping);
retVal |= function_namespace0_generated_332_begin(server, &nsMapping);
retVal |= function_namespace0_generated_333_begin(server, &nsMapping);
retVal |= function_namespace0_generated_334_begin(server, &nsMapping);
retVal |= function_namespace0_generated_335_begin(server, &nsMapping);
retVal |= function_namespace0_generated_336_begin(server, &nsMapping);
retVal |= function_namespace0_generated_337_begin(server, &nsMapping);
retVal |= function_namespace0_generated_338_begin(server, &nsMapping);
retVal |= function_namespace0_generated_339_begin(server, &nsMapping);
retVal |= function_namespace0_generated_340_begin(server, &nsMapping);
retVal |= function_namespace0_generated_341_begin(server, &nsMapping);
retVal |= function_namespace0_generated_342_begin(server, &nsMapping);
retVal |= function_namespace0_generated_343_begin(server, &nsMapping);
retVal |= function_namespace0_generated_344_begin(server, &nsMapping);
retVal |= function_namespace0_generated_345_begin(server, &nsMapping);
retVal |= function_namespace0_generated_346_begin(server, &nsMapping);
retVal |= function_namespace0_generated_347_begin(server, &nsMapping);
retVal |= function_namespace0_generated_348_begin(server, &nsMapping);
retVal |= function_namespace0_generated_349_begin(server, &nsMapping);
retVal |= function_namespace0_generated_350_begin(server, &nsMapping);
retVal |= function_namespace0_generated_351_begin(server, &nsMapping);
retVal |= function_namespace0_generated_352_begin(server, &nsMapping);
retVal |= function_namespace0_generated_353_begin(server, &nsMapping);
retVal |= function_namespace0_generated_354_begin(server, &nsMapping);
retVal |= function_namespace0_generated_355_begin(server, &nsMapping);
retVal |= function_namespace0_generated_356_begin(server, &nsMapping);
retVal |= function_namespace0_generated_357_begin(server, &nsMapping);
retVal |= function_namespace0_generated_358_begin(server, &nsMapping);
retVal |= function_namespace0_generated_359_begin(server, &nsMapping);
retVal |= function_namespace0_generated_360_begin(server, &nsMapping);
retVal |= function_namespace0_generated_361_begin(server, &nsMapping);
retVal |= function_namespace0_generated_362_begin(server, &nsMapping);
retVal |= function_namespace0_generated_363_begin(server, &nsMapping);
retVal |= function_namespace0_generated_364_begin(server, &nsMapping);
retVal |= function_namespace0_generated_365_begin(server, &nsMapping);
retVal |= function_namespace0_generated_366_begin(server, &nsMapping);
retVal |= function_namespace0_generated_367_begin(server, &nsMapping);
retVal |= function_namespace0_generated_368_begin(server, &nsMapping);
retVal |= function_namespace0_generated_369_begin(server, &nsMapping);
retVal |= function_namespace0_generated_370_begin(server, &nsMapping);
retVal |= function_namespace0_generated_371_begin(server, &nsMapping);
retVal |= function_namespace0_generated_372_begin(server, &nsMapping);
retVal |= function_namespace0_generated_373_begin(server, &nsMapping);
retVal |= function_namespace0_generated_374_begin(server, &nsMapping);
retVal |= function_namespace0_generated_375_begin(server, &nsMapping);
retVal |= function_namespace0_generated_376_begin(server, &nsMapping);
retVal |= function_namespace0_generated_377_begin(server, &nsMapping);
retVal |= function_namespace0_generated_378_begin(server, &nsMapping);
retVal |= function_namespace0_generated_379_begin(server, &nsMapping);
retVal |= function_namespace0_generated_380_begin(server, &nsMapping);
retVal |= function_namespace0_generated_381_begin(server, &nsMapping);
retVal |= function_namespace0_generated_382_begin(server, &nsMapping);
retVal |= function_namespace0_generated_383_begin(server, &nsMapping);
retVal |= function_namespace0_generated_384_begin(server, &nsMapping);
retVal |= function_namespace0_generated_385_begin(server, &nsMapping);
retVal |= function_namespace0_generated_386_begin(server, &nsMapping);
retVal |= function_namespace0_generated_387_begin(server, &nsMapping);
retVal |= function_namespace0_generated_388_begin(server, &nsMapping);
retVal |= function_namespace0_generated_389_begin(server, &nsMapping);
retVal |= function_namespace0_generated_390_begin(server, &nsMapping);
retVal |= function_namespace0_generated_391_begin(server, &nsMapping);
retVal |= function_namespace0_generated_392_begin(server, &nsMapping);
retVal |= function_namespace0_generated_393_begin(server, &nsMapping);
retVal |= function_namespace0_generated_394_begin(server, &nsMapping);
retVal |= function_namespace0_generated_395_begin(server, &nsMapping);
retVal |= function_namespace0_generated_396_begin(server, &nsMapping);
retVal |= function_namespace0_generated_397_begin(server, &nsMapping);
retVal |= function_namespace0_generated_398_begin(server, &nsMapping);
retVal |= function_namespace0_generated_399_begin(server, &nsMapping);
retVal |= function_namespace0_generated_400_begin(server, &nsMapping);
retVal |= function_namespace0_generated_401_begin(server, &nsMapping);
retVal |= function_namespace0_generated_402_begin(server, &nsMapping);
retVal |= function_namespace0_generated_403_begin(server, &nsMapping);
retVal |= function_namespace0_generated_404_begin(server, &nsMapping);
retVal |= function_namespace0_generated_405_begin(server, &nsMapping);
retVal |= function_namespace0_generated_406_begin(server, &nsMapping);
retVal |= function_namespace0_generated_407_begin(server, &nsMapping);
retVal |= function_namespace0_generated_408_begin(server, &nsMapping);
retVal |= function_namespace0_generated_409_begin(server, &nsMapping);
retVal |= function_namespace0_generated_410_begin(server, &nsMapping);
retVal |= function_namespace0_generated_411_begin(server, &nsMapping);
retVal |= function_namespace0_generated_412_begin(server, &nsMapping);
retVal |= function_namespace0_generated_413_begin(server, &nsMapping);
retVal |= function_namespace0_generated_414_begin(server, &nsMapping);
retVal |= function_namespace0_generated_415_begin(server, &nsMapping);
retVal |= function_namespace0_generated_416_begin(server, &nsMapping);
retVal |= function_namespace0_generated_417_begin(server, &nsMapping);
retVal |= function_namespace0_generated_418_begin(server, &nsMapping);
retVal |= function_namespace0_generated_419_begin(server, &nsMapping);
retVal |= function_namespace0_generated_420_begin(server, &nsMapping);
retVal |= function_namespace0_generated_421_begin(server, &nsMapping);
retVal |= function_namespace0_generated_422_begin(server, &nsMapping);
retVal |= function_namespace0_generated_423_begin(server, &nsMapping);
retVal |= function_namespace0_generated_424_begin(server, &nsMapping);
retVal |= function_namespace0_generated_425_begin(server, &nsMapping);
retVal |= function_namespace0_generated_426_begin(server, &nsMapping);
retVal |= function_namespace0_generated_427_begin(server, &nsMapping);
retVal |= function_namespace0_generated_428_begin(server, &nsMapping);
retVal |= function_namespace0_generated_429_begin(server, &nsMapping);
retVal |= function_namespace0_generated_430_begin(server, &nsMapping);
retVal |= function_namespace0_generated_431_begin(server, &nsMapping);
retVal |= function_namespace0_generated_432_begin(server, &nsMapping);
retVal |= function_namespace0_generated_433_begin(server, &nsMapping);
retVal |= function_namespace0_generated_434_begin(server, &nsMapping);
retVal |= function_namespace0_generated_435_begin(server, &nsMapping);
retVal |= function_namespace0_generated_436_begin(server, &nsMapping);
retVal |= function_namespace0_generated_437_begin(server, &nsMapping);
retVal |= function_namespace0_generated_438_begin(server, &nsMapping);
retVal |= function_namespace0_generated_439_begin(server, &nsMapping);
retVal |= function_namespace0_generated_440_begin(server, &nsMapping);
retVal |= function_namespace0_generated_441_begin(server, &nsMapping);
retVal |= function_namespace0_generated_442_begin(server, &nsMapping);
retVal |= function_namespace0_generated_443_begin(server, &nsMapping);
retVal |= function_namespace0_generated_444_begin(server, &nsMapping);
retVal |= function_namespace0_generated_445_begin(server, &nsMapping);
retVal |= function_namespace0_generated_446_begin(server, &nsMapping);
retVal |= function_namespace0_generated_447_begin(server, &nsMapping);
retVal |= function_namespace0_generated_448_begin(server, &nsMapping);
retVal |= function_namespace0_generated_449_begin(server, &nsMapping);
retVal |= function_namespace0_generated_450_begin(server, &nsMapping);
retVal |= function_namespace0_generated_451_begin(server, &nsMapping);
retVal |= function_namespace0_generated_452_begin(server, &nsMapping);
retVal |= function_namespace0_generated_453_begin(server, &nsMapping);
retVal |= function_namespace0_generated_454_begin(server, &nsMapping);
retVal |= function_namespace0_generated_455_begin(server, &nsMapping);
retVal |= function_namespace0_generated_456_begin(server, &nsMapping);
retVal |= function_namespace0_generated_457_begin(server, &nsMapping);
retVal |= function_namespace0_generated_458_begin(server, &nsMapping);
retVal |= function_namespace0_generated_459_begin(server, &nsMapping);
retVal |= function_namespace0_generated_460_begin(server, &nsMapping);
retVal |= function_namespace0_generated_461_begin(server, &nsMapping);
retVal |= function_namespace0_generated_462_begin(server, &nsMapping);
retVal |= function_namespace0_generated_463_begin(server, &nsMapping);
retVal |= function_namespace0_generated_464_begin(server, &nsMapping);
retVal |= function_namespace0_generated_465_begin(server, &nsMapping);
retVal |= function_namespace0_generated_466_begin(server, &nsMapping);
retVal |= function_namespace0_generated_467_begin(server, &nsMapping);
retVal |= function_namespace0_generated_468_begin(server, &nsMapping);
retVal |= function_namespace0_generated_469_begin(server, &nsMapping);
retVal |= function_namespace0_generated_470_begin(server, &nsMapping);
retVal |= function_namespace0_generated_471_begin(server, &nsMapping);
retVal |= function_namespace0_generated_472_begin(server, &nsMapping);
retVal |= function_namespace0_generated_473_begin(server, &nsMapping);
retVal |= function_namespace0_generated_474_begin(server, &nsMapping);
retVal |= function_namespace0_generated_475_begin(server, &nsMapping);
retVal |= function_namespace0_generated_476_begin(server, &nsMapping);
retVal |= function_namespace0_generated_477_begin(server, &nsMapping);
retVal |= function_namespace0_generated_478_begin(server, &nsMapping);
retVal |= function_namespace0_generated_479_begin(server, &nsMapping);
retVal |= function_namespace0_generated_480_begin(server, &nsMapping);
retVal |= function_namespace0_generated_481_begin(server, &nsMapping);
retVal |= function_namespace0_generated_482_begin(server, &nsMapping);
retVal |= function_namespace0_generated_483_begin(server, &nsMapping);
retVal |= function_namespace0_generated_484_begin(server, &nsMapping);
retVal |= function_namespace0_generated_485_begin(server, &nsMapping);
retVal |= function_namespace0_generated_486_begin(server, &nsMapping);
retVal |= function_namespace0_generated_487_begin(server, &nsMapping);
retVal |= function_namespace0_generated_488_begin(server, &nsMapping);
retVal |= function_namespace0_generated_489_begin(server, &nsMapping);
retVal |= function_namespace0_generated_490_begin(server, &nsMapping);
retVal |= function_namespace0_generated_491_begin(server, &nsMapping);
retVal |= function_namespace0_generated_492_begin(server, &nsMapping);
retVal |= function_namespace0_generated_493_begin(server, &nsMapping);
retVal |= function_namespace0_generated_494_begin(server, &nsMapping);
retVal |= function_namespace0_generated_495_begin(server, &nsMapping);
retVal |= function_namespace0_generated_496_begin(server, &nsMapping);
retVal |= function_namespace0_generated_497_begin(server, &nsMapping);
retVal |= function_namespace0_generated_498_begin(server, &nsMapping);
retVal |= function_namespace0_generated_499_begin(server, &nsMapping);
retVal |= function_namespace0_generated_500_begin(server, &nsMapping);
retVal |= function_namespace0_generated_501_begin(server, &nsMapping);
retVal |= function_namespace0_generated_502_begin(server, &nsMapping);
retVal |= function_namespace0_generated_503_begin(server, &nsMapping);
retVal |= function_namespace0_generated_504_begin(server, &nsMapping);
retVal |= function_namespace0_generated_505_begin(server, &nsMapping);
retVal |= function_namespace0_generated_506_begin(server, &nsMapping);
retVal |= function_namespace0_generated_507_begin(server, &nsMapping);
retVal |= function_namespace0_generated_508_begin(server, &nsMapping);
retVal |= function_namespace0_generated_509_begin(server, &nsMapping);
retVal |= function_namespace0_generated_510_begin(server, &nsMapping);
retVal |= function_namespace0_generated_511_begin(server, &nsMapping);
retVal |= function_namespace0_generated_512_begin(server, &nsMapping);
retVal |= function_namespace0_generated_513_begin(server, &nsMapping);
retVal |= function_namespace0_generated_514_begin(server, &nsMapping);
retVal |= function_namespace0_generated_515_begin(server, &nsMapping);
retVal |= function_namespace0_generated_516_begin(server, &nsMapping);
retVal |= function_namespace0_generated_517_begin(server, &nsMapping);
retVal |= function_namespace0_generated_518_begin(server, &nsMapping);
retVal |= function_namespace0_generated_519_begin(server, &nsMapping);
retVal |= function_namespace0_generated_520_begin(server, &nsMapping);
retVal |= function_namespace0_generated_521_begin(server, &nsMapping);
retVal |= function_namespace0_generated_522_begin(server, &nsMapping);
retVal |= function_namespace0_generated_523_begin(server, &nsMapping);
retVal |= function_namespace0_generated_524_begin(server, &nsMapping);
retVal |= function_namespace0_generated_525_begin(server, &nsMapping);
retVal |= function_namespace0_generated_526_begin(server, &nsMapping);
retVal |= function_namespace0_generated_527_begin(server, &nsMapping);
retVal |= function_namespace0_generated_528_begin(server, &nsMapping);
retVal |= function_namespace0_generated_529_begin(server, &nsMapping);
retVal |= function_namespace0_generated_530_begin(server, &nsMapping);
retVal |= function_namespace0_generated_531_begin(server, &nsMapping);
retVal |= function_namespace0_generated_532_begin(server, &nsMapping);
retVal |= function_namespace0_generated_533_begin(server, &nsMapping);
retVal |= function_namespace0_generated_534_begin(server, &nsMapping);
retVal |= function_namespace0_generated_535_begin(server, &nsMapping);
retVal |= function_namespace0_generated_536_begin(server, &nsMapping);
retVal |= function_namespace0_generated_537_begin(server, &nsMapping);
retVal |= function_namespace0_generated_538_begin(server, &nsMapping);
retVal |= function_namespace0_generated_539_begin(server, &nsMapping);
retVal |= function_namespace0_generated_540_begin(server, &nsMapping);
retVal |= function_namespace0_generated_541_begin(server, &nsMapping);
retVal |= function_namespace0_generated_542_begin(server, &nsMapping);
retVal |= function_namespace0_generated_543_begin(server, &nsMapping);
retVal |= function_namespace0_generated_544_begin(server, &nsMapping);
retVal |= function_namespace0_generated_545_begin(server, &nsMapping);
retVal |= function_namespace0_generated_546_begin(server, &nsMapping);
retVal |= function_namespace0_generated_547_begin(server, &nsMapping);
retVal |= function_namespace0_generated_548_begin(server, &nsMapping);
retVal |= function_namespace0_generated_549_begin(server, &nsMapping);
retVal |= function_namespace0_generated_550_begin(server, &nsMapping);
retVal |= function_namespace0_generated_551_begin(server, &nsMapping);
retVal |= function_namespace0_generated_552_begin(server, &nsMapping);
retVal |= function_namespace0_generated_553_begin(server, &nsMapping);
retVal |= function_namespace0_generated_554_begin(server, &nsMapping);
retVal |= function_namespace0_generated_555_begin(server, &nsMapping);
retVal |= function_namespace0_generated_556_begin(server, &nsMapping);
retVal |= function_namespace0_generated_557_begin(server, &nsMapping);
retVal |= function_namespace0_generated_558_begin(server, &nsMapping);
retVal |= function_namespace0_generated_559_begin(server, &nsMapping);
retVal |= function_namespace0_generated_560_begin(server, &nsMapping);
retVal |= function_namespace0_generated_561_begin(server, &nsMapping);
retVal |= function_namespace0_generated_562_begin(server, &nsMapping);
retVal |= function_namespace0_generated_563_begin(server, &nsMapping);
retVal |= function_namespace0_generated_564_begin(server, &nsMapping);
retVal |= function_namespace0_generated_565_begin(server, &nsMapping);
retVal |= function_namespace0_generated_566_begin(server, &nsMapping);
retVal |= function_namespace0_generated_567_begin(server, &nsMapping);
retVal |= function_namespace0_generated_568_begin(server, &nsMapping);
retVal |= function_namespace0_generated_569_begin(server, &nsMapping);
retVal |= function_namespace0_generated_570_begin(server, &nsMapping);
retVal |= function_namespace0_generated_571_begin(server, &nsMapping);
retVal |= function_namespace0_generated_572_begin(server, &nsMapping);
retVal |= function_namespace0_generated_573_begin(server, &nsMapping);
retVal |= function_namespace0_generated_574_begin(server, &nsMapping);
retVal |= function_namespace0_generated_575_begin(server, &nsMapping);
retVal |= function_namespace0_generated_576_begin(server, &nsMapping);
retVal |= function_namespace0_generated_577_begin(server, &nsMapping);
retVal |= function_namespace0_generated_578_begin(server, &nsMapping);
retVal |= function_namespace0_generated_579_begin(server, &nsMapping);
retVal |= function_namespace0_generated_580_begin(server, &nsMapping);
retVal |= function_namespace0_generated_581_begin(server, &nsMapping);
retVal |= function_namespace0_generated_582_begin(server, &nsMapping);
retVal |= function_namespace0_generated_583_begin(server, &nsMapping);
retVal |= function_namespace0_generated_584_begin(server, &nsMapping);
retVal |= function_namespace0_generated_585_begin(server, &nsMapping);
retVal |= function_namespace0_generated_586_begin(server, &nsMapping);
retVal |= function_namespace0_generated_587_begin(server, &nsMapping);
retVal |= function_namespace0_generated_588_begin(server, &nsMapping);
retVal |= function_namespace0_generated_589_begin(server, &nsMapping);
retVal |= function_namespace0_generated_590_begin(server, &nsMapping);
retVal |= function_namespace0_generated_591_begin(server, &nsMapping);
retVal |= function_namespace0_generated_592_begin(server, &nsMapping);
retVal |= function_namespace0_generated_593_begin(server, &nsMapping);
retVal |= function_namespace0_generated_594_begin(server, &nsMapping);
retVal |= function_namespace0_generated_595_begin(server, &nsMapping);
retVal |= function_namespace0_generated_596_begin(server, &nsMapping);
retVal |= function_namespace0_generated_597_begin(server, &nsMapping);
retVal |= function_namespace0_generated_598_begin(server, &nsMapping);
retVal |= function_namespace0_generated_599_begin(server, &nsMapping);
retVal |= function_namespace0_generated_600_begin(server, &nsMapping);
retVal |= function_namespace0_generated_601_begin(server, &nsMapping);
retVal |= function_namespace0_generated_602_begin(server, &nsMapping);
retVal |= function_namespace0_generated_603_begin(server, &nsMapping);
retVal |= function_namespace0_generated_604_begin(server, &nsMapping);
retVal |= function_namespace0_generated_605_begin(server, &nsMapping);
retVal |= function_namespace0_generated_606_begin(server, &nsMapping);
retVal |= function_namespace0_generated_607_begin(server, &nsMapping);
retVal |= function_namespace0_generated_608_begin(server, &nsMapping);
retVal |= function_namespace0_generated_609_begin(server, &nsMapping);
retVal |= function_namespace0_generated_610_begin(server, &nsMapping);
retVal |= function_namespace0_generated_611_begin(server, &nsMapping);
retVal |= function_namespace0_generated_612_begin(server, &nsMapping);
retVal |= function_namespace0_generated_613_begin(server, &nsMapping);
retVal |= function_namespace0_generated_614_begin(server, &nsMapping);
retVal |= function_namespace0_generated_615_begin(server, &nsMapping);
retVal |= function_namespace0_generated_616_begin(server, &nsMapping);
retVal |= function_namespace0_generated_617_begin(server, &nsMapping);
retVal |= function_namespace0_generated_618_begin(server, &nsMapping);
retVal |= function_namespace0_generated_619_begin(server, &nsMapping);
retVal |= function_namespace0_generated_620_begin(server, &nsMapping);
retVal |= function_namespace0_generated_621_begin(server, &nsMapping);
retVal |= function_namespace0_generated_622_begin(server, &nsMapping);
retVal |= function_namespace0_generated_623_begin(server, &nsMapping);
retVal |= function_namespace0_generated_624_begin(server, &nsMapping);
retVal |= function_namespace0_generated_625_begin(server, &nsMapping);
retVal |= function_namespace0_generated_626_begin(server, &nsMapping);
retVal |= function_namespace0_generated_627_begin(server, &nsMapping);
retVal |= function_namespace0_generated_628_begin(server, &nsMapping);
retVal |= function_namespace0_generated_629_begin(server, &nsMapping);
retVal |= function_namespace0_generated_630_begin(server, &nsMapping);
retVal |= function_namespace0_generated_631_begin(server, &nsMapping);
retVal |= function_namespace0_generated_632_begin(server, &nsMapping);
retVal |= function_namespace0_generated_633_begin(server, &nsMapping);
retVal |= function_namespace0_generated_634_begin(server, &nsMapping);
retVal |= function_namespace0_generated_635_begin(server, &nsMapping);
retVal |= function_namespace0_generated_636_begin(server, &nsMapping);
retVal |= function_namespace0_generated_637_begin(server, &nsMapping);
retVal |= function_namespace0_generated_638_begin(server, &nsMapping);
retVal |= function_namespace0_generated_639_begin(server, &nsMapping);
retVal |= function_namespace0_generated_640_begin(server, &nsMapping);
retVal |= function_namespace0_generated_641_begin(server, &nsMapping);
retVal |= function_namespace0_generated_642_begin(server, &nsMapping);
retVal |= function_namespace0_generated_643_begin(server, &nsMapping);
retVal |= function_namespace0_generated_644_begin(server, &nsMapping);
retVal |= function_namespace0_generated_645_begin(server, &nsMapping);
retVal |= function_namespace0_generated_646_begin(server, &nsMapping);
retVal |= function_namespace0_generated_647_begin(server, &nsMapping);
retVal |= function_namespace0_generated_648_begin(server, &nsMapping);
retVal |= function_namespace0_generated_649_begin(server, &nsMapping);
retVal |= function_namespace0_generated_650_begin(server, &nsMapping);
retVal |= function_namespace0_generated_651_begin(server, &nsMapping);
retVal |= function_namespace0_generated_652_begin(server, &nsMapping);
retVal |= function_namespace0_generated_653_begin(server, &nsMapping);
retVal |= function_namespace0_generated_654_begin(server, &nsMapping);
retVal |= function_namespace0_generated_655_begin(server, &nsMapping);
retVal |= function_namespace0_generated_656_begin(server, &nsMapping);
retVal |= function_namespace0_generated_657_begin(server, &nsMapping);
retVal |= function_namespace0_generated_658_begin(server, &nsMapping);
retVal |= function_namespace0_generated_659_begin(server, &nsMapping);
retVal |= function_namespace0_generated_660_begin(server, &nsMapping);
retVal |= function_namespace0_generated_661_begin(server, &nsMapping);
retVal |= function_namespace0_generated_662_begin(server, &nsMapping);
retVal |= function_namespace0_generated_663_begin(server, &nsMapping);
retVal |= function_namespace0_generated_664_begin(server, &nsMapping);
retVal |= function_namespace0_generated_665_begin(server, &nsMapping);
retVal |= function_namespace0_generated_666_begin(server, &nsMapping);
retVal |= function_namespace0_generated_667_begin(server, &nsMapping);
retVal |= function_namespace0_generated_668_begin(server, &nsMapping);
retVal |= function_namespace0_generated_669_begin(server, &nsMapping);
retVal |= function_namespace0_generated_670_begin(server, &nsMapping);
retVal |= function_namespace0_generated_671_begin(server, &nsMapping);
retVal |= function_namespace0_generated_672_begin(server, &nsMapping);
retVal |= function_namespace0_generated_673_begin(server, &nsMapping);
retVal |= function_namespace0_generated_674_begin(server, &nsMapping);
retVal |= function_namespace0_generated_675_begin(server, &nsMapping);
retVal |= function_namespace0_generated_676_begin(server, &nsMapping);
retVal |= function_namespace0_generated_677_begin(server, &nsMapping);
retVal |= function_namespace0_generated_678_begin(server, &nsMapping);
retVal |= function_namespace0_generated_679_begin(server, &nsMapping);
retVal |= function_namespace0_generated_680_begin(server, &nsMapping);
retVal |= function_namespace0_generated_681_begin(server, &nsMapping);
retVal |= function_namespace0_generated_682_begin(server, &nsMapping);
retVal |= function_namespace0_generated_683_begin(server, &nsMapping);
retVal |= function_namespace0_generated_684_begin(server, &nsMapping);
retVal |= function_namespace0_generated_685_begin(server, &nsMapping);
retVal |= function_namespace0_generated_686_begin(server, &nsMapping);
retVal |= function_namespace0_generated_687_begin(server, &nsMapping);
retVal |= function_namespace0_generated_688_begin(server, &nsMapping);
retVal |= function_namespace0_generated_689_begin(server, &nsMapping);
retVal |= function_namespace0_generated_690_begin(server, &nsMapping);
retVal |= function_namespace0_generated_691_begin(server, &nsMapping);
retVal |= function_namespace0_generated_692_begin(server, &nsMapping);
retVal |= function_namespace0_generated_693_begin(server, &nsMapping);
retVal |= function_namespace0_generated_694_begin(server, &nsMapping);
retVal |= function_namespace0_generated_695_begin(server, &nsMapping);
retVal |= function_namespace0_generated_696_begin(server, &nsMapping);
retVal |= function_namespace0_generated_697_begin(server, &nsMapping);
retVal |= function_namespace0_generated_698_begin(server, &nsMapping);
retVal |= function_namespace0_generated_699_begin(server, &nsMapping);
retVal |= function_namespace0_generated_700_begin(server, &nsMapping);
retVal |= function_namespace0_generated_701_begin(server, &nsMapping);
retVal |= function_namespace0_generated_702_begin(server, &nsMapping);
retVal |= function_namespace0_generated_703_begin(server, &nsMapping);
retVal |= function_namespace0_generated_704_begin(server, &nsMapping);
retVal |= function_namespace0_generated_705_begin(server, &nsMapping);
retVal |= function_namespace0_generated_706_begin(server, &nsMapping);
retVal |= function_namespace0_generated_707_begin(server, &nsMapping);
retVal |= function_namespace0_generated_708_begin(server, &nsMapping);
retVal |= function_namespace0_generated_709_begin(server, &nsMapping);
retVal |= function_namespace0_generated_710_begin(server, &nsMapping);
retVal |= function_namespace0_generated_711_begin(server, &nsMapping);
retVal |= function_namespace0_generated_712_begin(server, &nsMapping);
retVal |= function_namespace0_generated_713_begin(server, &nsMapping);
retVal |= function_namespace0_generated_714_begin(server, &nsMapping);
retVal |= function_namespace0_generated_715_begin(server, &nsMapping);
retVal |= function_namespace0_generated_716_begin(server, &nsMapping);
retVal |= function_namespace0_generated_717_begin(server, &nsMapping);
retVal |= function_namespace0_generated_718_begin(server, &nsMapping);
retVal |= function_namespace0_generated_719_begin(server, &nsMapping);
retVal |= function_namespace0_generated_720_begin(server, &nsMapping);
retVal |= function_namespace0_generated_721_begin(server, &nsMapping);
retVal |= function_namespace0_generated_722_begin(server, &nsMapping);
retVal |= function_namespace0_generated_723_begin(server, &nsMapping);
retVal |= function_namespace0_generated_724_begin(server, &nsMapping);
retVal |= function_namespace0_generated_725_begin(server, &nsMapping);
retVal |= function_namespace0_generated_726_begin(server, &nsMapping);
retVal |= function_namespace0_generated_727_begin(server, &nsMapping);
retVal |= function_namespace0_generated_728_begin(server, &nsMapping);
retVal |= function_namespace0_generated_729_begin(server, &nsMapping);
retVal |= function_namespace0_generated_730_begin(server, &nsMapping);
retVal |= function_namespace0_generated_731_begin(server, &nsMapping);
retVal |= function_namespace0_generated_732_begin(server, &nsMapping);
retVal |= function_namespace0_generated_733_begin(server, &nsMapping);
retVal |= function_namespace0_generated_734_begin(server, &nsMapping);
retVal |= function_namespace0_generated_735_begin(server, &nsMapping);
retVal |= function_namespace0_generated_736_begin(server, &nsMapping);
retVal |= function_namespace0_generated_737_begin(server, &nsMapping);
retVal |= function_namespace0_generated_738_begin(server, &nsMapping);
retVal |= function_namespace0_generated_739_begin(server, &nsMapping);
retVal |= function_namespace0_generated_740_begin(server, &nsMapping);
retVal |= function_namespace0_generated_741_begin(server, &nsMapping);
retVal |= function_namespace0_generated_742_begin(server, &nsMapping);
retVal |= function_namespace0_generated_743_begin(server, &nsMapping);
retVal |= function_namespace0_generated_744_begin(server, &nsMapping);
retVal |= function_namespace0_generated_745_begin(server, &nsMapping);
retVal |= function_namespace0_generated_746_begin(server, &nsMapping);
retVal |= function_namespace0_generated_747_begin(server, &nsMapping);
retVal |= function_namespace0_generated_748_begin(server, &nsMapping);
retVal |= function_namespace0_generated_749_begin(server, &nsMapping);
retVal |= function_namespace0_generated_750_begin(server, &nsMapping);
retVal |= function_namespace0_generated_751_begin(server, &nsMapping);
retVal |= function_namespace0_generated_752_begin(server, &nsMapping);
retVal |= function_namespace0_generated_753_begin(server, &nsMapping);
retVal |= function_namespace0_generated_754_begin(server, &nsMapping);
retVal |= function_namespace0_generated_755_begin(server, &nsMapping);
retVal |= function_namespace0_generated_756_begin(server, &nsMapping);
retVal |= function_namespace0_generated_757_begin(server, &nsMapping);
retVal |= function_namespace0_generated_758_begin(server, &nsMapping);
retVal |= function_namespace0_generated_759_begin(server, &nsMapping);
retVal |= function_namespace0_generated_760_begin(server, &nsMapping);
retVal |= function_namespace0_generated_761_begin(server, &nsMapping);
retVal |= function_namespace0_generated_762_begin(server, &nsMapping);
retVal |= function_namespace0_generated_763_begin(server, &nsMapping);
retVal |= function_namespace0_generated_764_begin(server, &nsMapping);
retVal |= function_namespace0_generated_765_begin(server, &nsMapping);
retVal |= function_namespace0_generated_766_begin(server, &nsMapping);
retVal |= function_namespace0_generated_767_begin(server, &nsMapping);
retVal |= function_namespace0_generated_768_begin(server, &nsMapping);
retVal |= function_namespace0_generated_769_begin(server, &nsMapping);
retVal |= function_namespace0_generated_770_begin(server, &nsMapping);
retVal |= function_namespace0_generated_771_begin(server, &nsMapping);
retVal |= function_namespace0_generated_772_begin(server, &nsMapping);
retVal |= function_namespace0_generated_773_begin(server, &nsMapping);
retVal |= function_namespace0_generated_774_begin(server, &nsMapping);
retVal |= function_namespace0_generated_775_begin(server, &nsMapping);
retVal |= function_namespace0_generated_776_begin(server, &nsMapping);
retVal |= function_namespace0_generated_777_begin(server, &nsMapping);
retVal |= function_namespace0_generated_778_begin(server, &nsMapping);
retVal |= function_namespace0_generated_779_begin(server, &nsMapping);
retVal |= function_namespace0_generated_780_begin(server, &nsMapping);
retVal |= function_namespace0_generated_781_begin(server, &nsMapping);
retVal |= function_namespace0_generated_782_begin(server, &nsMapping);
retVal |= function_namespace0_generated_783_begin(server, &nsMapping);
retVal |= function_namespace0_generated_784_begin(server, &nsMapping);
retVal |= function_namespace0_generated_785_begin(server, &nsMapping);
retVal |= function_namespace0_generated_786_begin(server, &nsMapping);
retVal |= function_namespace0_generated_787_begin(server, &nsMapping);
retVal |= function_namespace0_generated_788_begin(server, &nsMapping);
retVal |= function_namespace0_generated_789_begin(server, &nsMapping);
retVal |= function_namespace0_generated_790_begin(server, &nsMapping);
retVal |= function_namespace0_generated_791_begin(server, &nsMapping);
retVal |= function_namespace0_generated_792_begin(server, &nsMapping);
retVal |= function_namespace0_generated_793_begin(server, &nsMapping);
retVal |= function_namespace0_generated_794_begin(server, &nsMapping);
retVal |= function_namespace0_generated_795_begin(server, &nsMapping);
retVal |= function_namespace0_generated_796_begin(server, &nsMapping);
retVal |= function_namespace0_generated_797_begin(server, &nsMapping);
retVal |= function_namespace0_generated_798_begin(server, &nsMapping);
retVal |= function_namespace0_generated_799_begin(server, &nsMapping);
retVal |= function_namespace0_generated_800_begin(server, &nsMapping);
retVal |= function_namespace0_generated_801_begin(server, &nsMapping);
retVal |= function_namespace0_generated_802_begin(server, &nsMapping);
retVal |= function_namespace0_generated_803_begin(server, &nsMapping);
retVal |= function_namespace0_generated_804_begin(server, &nsMapping);
retVal |= function_namespace0_generated_805_begin(server, &nsMapping);
retVal |= function_namespace0_generated_806_begin(server, &nsMapping);
retVal |= function_namespace0_generated_807_begin(server, &nsMapping);
retVal |= function_namespace0_generated_808_begin(server, &nsMapping);
retVal |= function_namespace0_generated_809_begin(server, &nsMapping);
retVal |= function_namespace0_generated_810_begin(server, &nsMapping);
retVal |= function_namespace0_generated_811_begin(server, &nsMapping);
retVal |= function_namespace0_generated_812_begin(server, &nsMapping);
retVal |= function_namespace0_generated_813_begin(server, &nsMapping);
retVal |= function_namespace0_generated_814_begin(server, &nsMapping);
retVal |= function_namespace0_generated_815_begin(server, &nsMapping);
retVal |= function_namespace0_generated_816_begin(server, &nsMapping);
retVal |= function_namespace0_generated_817_begin(server, &nsMapping);
retVal |= function_namespace0_generated_818_begin(server, &nsMapping);
retVal |= function_namespace0_generated_819_begin(server, &nsMapping);
retVal |= function_namespace0_generated_820_begin(server, &nsMapping);
retVal |= function_namespace0_generated_821_begin(server, &nsMapping);
retVal |= function_namespace0_generated_822_begin(server, &nsMapping);
retVal |= function_namespace0_generated_823_begin(server, &nsMapping);
retVal |= function_namespace0_generated_824_begin(server, &nsMapping);
retVal |= function_namespace0_generated_825_begin(server, &nsMapping);
retVal |= function_namespace0_generated_826_begin(server, &nsMapping);
retVal |= function_namespace0_generated_827_begin(server, &nsMapping);
retVal |= function_namespace0_generated_828_begin(server, &nsMapping);
retVal |= function_namespace0_generated_829_begin(server, &nsMapping);
retVal |= function_namespace0_generated_830_begin(server, &nsMapping);
retVal |= function_namespace0_generated_831_begin(server, &nsMapping);
retVal |= function_namespace0_generated_832_begin(server, &nsMapping);
retVal |= function_namespace0_generated_833_begin(server, &nsMapping);
retVal |= function_namespace0_generated_834_begin(server, &nsMapping);
retVal |= function_namespace0_generated_834_finish(server, &nsMapping);
retVal |= function_namespace0_generated_833_finish(server, &nsMapping);
retVal |= function_namespace0_generated_832_finish(server, &nsMapping);
retVal |= function_namespace0_generated_831_finish(server, &nsMapping);
retVal |= function_namespace0_generated_830_finish(server, &nsMapping);
retVal |= function_namespace0_generated_829_finish(server, &nsMapping);
retVal |= function_namespace0_generated_828_finish(server, &nsMapping);
retVal |= function_namespace0_generated_827_finish(server, &nsMapping);
retVal |= function_namespace0_generated_826_finish(server, &nsMapping);
retVal |= function_namespace0_generated_825_finish(server, &nsMapping);
retVal |= function_namespace0_generated_824_finish(server, &nsMapping);
retVal |= function_namespace0_generated_823_finish(server, &nsMapping);
retVal |= function_namespace0_generated_822_finish(server, &nsMapping);
retVal |= function_namespace0_generated_821_finish(server, &nsMapping);
retVal |= function_namespace0_generated_820_finish(server, &nsMapping);
retVal |= function_namespace0_generated_819_finish(server, &nsMapping);
retVal |= function_namespace0_generated_818_finish(server, &nsMapping);
retVal |= function_namespace0_generated_817_finish(server, &nsMapping);
retVal |= function_namespace0_generated_816_finish(server, &nsMapping);
retVal |= function_namespace0_generated_815_finish(server, &nsMapping);
retVal |= function_namespace0_generated_814_finish(server, &nsMapping);
retVal |= function_namespace0_generated_813_finish(server, &nsMapping);
retVal |= function_namespace0_generated_812_finish(server, &nsMapping);
retVal |= function_namespace0_generated_811_finish(server, &nsMapping);
retVal |= function_namespace0_generated_810_finish(server, &nsMapping);
retVal |= function_namespace0_generated_809_finish(server, &nsMapping);
retVal |= function_namespace0_generated_808_finish(server, &nsMapping);
retVal |= function_namespace0_generated_807_finish(server, &nsMapping);
retVal |= function_namespace0_generated_806_finish(server, &nsMapping);
retVal |= function_namespace0_generated_805_finish(server, &nsMapping);
retVal |= function_namespace0_generated_804_finish(server, &nsMapping);
retVal |= function_namespace0_generated_803_finish(server, &nsMapping);
retVal |= function_namespace0_generated_802_finish(server, &nsMapping);
retVal |= function_namespace0_generated_801_finish(server, &nsMapping);
retVal |= function_namespace0_generated_800_finish(server, &nsMapping);
retVal |= function_namespace0_generated_799_finish(server, &nsMapping);
retVal |= function_namespace0_generated_798_finish(server, &nsMapping);
retVal |= function_namespace0_generated_797_finish(server, &nsMapping);
retVal |= function_namespace0_generated_796_finish(server, &nsMapping);
retVal |= function_namespace0_generated_795_finish(server, &nsMapping);
retVal |= function_namespace0_generated_794_finish(server, &nsMapping);
retVal |= function_namespace0_generated_793_finish(server, &nsMapping);
retVal |= function_namespace0_generated_792_finish(server, &nsMapping);
retVal |= function_namespace0_generated_791_finish(server, &nsMapping);
retVal |= function_namespace0_generated_790_finish(server, &nsMapping);
retVal |= function_namespace0_generated_789_finish(server, &nsMapping);
retVal |= function_namespace0_generated_788_finish(server, &nsMapping);
retVal |= function_namespace0_generated_787_finish(server, &nsMapping);
retVal |= function_namespace0_generated_786_finish(server, &nsMapping);
retVal |= function_namespace0_generated_785_finish(server, &nsMapping);
retVal |= function_namespace0_generated_784_finish(server, &nsMapping);
retVal |= function_namespace0_generated_783_finish(server, &nsMapping);
retVal |= function_namespace0_generated_782_finish(server, &nsMapping);
retVal |= function_namespace0_generated_781_finish(server, &nsMapping);
retVal |= function_namespace0_generated_780_finish(server, &nsMapping);
retVal |= function_namespace0_generated_779_finish(server, &nsMapping);
retVal |= function_namespace0_generated_778_finish(server, &nsMapping);
retVal |= function_namespace0_generated_777_finish(server, &nsMapping);
retVal |= function_namespace0_generated_776_finish(server, &nsMapping);
retVal |= function_namespace0_generated_775_finish(server, &nsMapping);
retVal |= function_namespace0_generated_774_finish(server, &nsMapping);
retVal |= function_namespace0_generated_773_finish(server, &nsMapping);
retVal |= function_namespace0_generated_772_finish(server, &nsMapping);
retVal |= function_namespace0_generated_771_finish(server, &nsMapping);
retVal |= function_namespace0_generated_770_finish(server, &nsMapping);
retVal |= function_namespace0_generated_769_finish(server, &nsMapping);
retVal |= function_namespace0_generated_768_finish(server, &nsMapping);
retVal |= function_namespace0_generated_767_finish(server, &nsMapping);
retVal |= function_namespace0_generated_766_finish(server, &nsMapping);
retVal |= function_namespace0_generated_765_finish(server, &nsMapping);
retVal |= function_namespace0_generated_764_finish(server, &nsMapping);
retVal |= function_namespace0_generated_763_finish(server, &nsMapping);
retVal |= function_namespace0_generated_762_finish(server, &nsMapping);
retVal |= function_namespace0_generated_761_finish(server, &nsMapping);
retVal |= function_namespace0_generated_760_finish(server, &nsMapping);
retVal |= function_namespace0_generated_759_finish(server, &nsMapping);
retVal |= function_namespace0_generated_758_finish(server, &nsMapping);
retVal |= function_namespace0_generated_757_finish(server, &nsMapping);
retVal |= function_namespace0_generated_756_finish(server, &nsMapping);
retVal |= function_namespace0_generated_755_finish(server, &nsMapping);
retVal |= function_namespace0_generated_754_finish(server, &nsMapping);
retVal |= function_namespace0_generated_753_finish(server, &nsMapping);
retVal |= function_namespace0_generated_752_finish(server, &nsMapping);
retVal |= function_namespace0_generated_751_finish(server, &nsMapping);
retVal |= function_namespace0_generated_750_finish(server, &nsMapping);
retVal |= function_namespace0_generated_749_finish(server, &nsMapping);
retVal |= function_namespace0_generated_748_finish(server, &nsMapping);
retVal |= function_namespace0_generated_747_finish(server, &nsMapping);
retVal |= function_namespace0_generated_746_finish(server, &nsMapping);
retVal |= function_namespace0_generated_745_finish(server, &nsMapping);
retVal |= function_namespace0_generated_744_finish(server, &nsMapping);
retVal |= function_namespace0_generated_743_finish(server, &nsMapping);
retVal |= function_namespace0_generated_742_finish(server, &nsMapping);
retVal |= function_namespace0_generated_741_finish(server, &nsMapping);
retVal |= function_namespace0_generated_740_finish(server, &nsMapping);
retVal |= function_namespace0_generated_739_finish(server, &nsMapping);
retVal |= function_namespace0_generated_738_finish(server, &nsMapping);
retVal |= function_namespace0_generated_737_finish(server, &nsMapping);
retVal |= function_namespace0_generated_736_finish(server, &nsMapping);
retVal |= function_namespace0_generated_735_finish(server, &nsMapping);
retVal |= function_namespace0_generated_734_finish(server, &nsMapping);
retVal |= function_namespace0_generated_733_finish(server, &nsMapping);
retVal |= function_namespace0_generated_732_finish(server, &nsMapping);
retVal |= function_namespace0_generated_731_finish(server, &nsMapping);
retVal |= function_namespace0_generated_730_finish(server, &nsMapping);
retVal |= function_namespace0_generated_729_finish(server, &nsMapping);
retVal |= function_namespace0_generated_728_finish(server, &nsMapping);
retVal |= function_namespace0_generated_727_finish(server, &nsMapping);
retVal |= function_namespace0_generated_726_finish(server, &nsMapping);
retVal |= function_namespace0_generated_725_finish(server, &nsMapping);
retVal |= function_namespace0_generated_724_finish(server, &nsMapping);
retVal |= function_namespace0_generated_723_finish(server, &nsMapping);
retVal |= function_namespace0_generated_722_finish(server, &nsMapping);
retVal |= function_namespace0_generated_721_finish(server, &nsMapping);
retVal |= function_namespace0_generated_720_finish(server, &nsMapping);
retVal |= function_namespace0_generated_719_finish(server, &nsMapping);
retVal |= function_namespace0_generated_718_finish(server, &nsMapping);
retVal |= function_namespace0_generated_717_finish(server, &nsMapping);
retVal |= function_namespace0_generated_716_finish(server, &nsMapping);
retVal |= function_namespace0_generated_715_finish(server, &nsMapping);
retVal |= function_namespace0_generated_714_finish(server, &nsMapping);
retVal |= function_namespace0_generated_713_finish(server, &nsMapping);
retVal |= function_namespace0_generated_712_finish(server, &nsMapping);
retVal |= function_namespace0_generated_711_finish(server, &nsMapping);
retVal |= function_namespace0_generated_710_finish(server, &nsMapping);
retVal |= function_namespace0_generated_709_finish(server, &nsMapping);
retVal |= function_namespace0_generated_708_finish(server, &nsMapping);
retVal |= function_namespace0_generated_707_finish(server, &nsMapping);
retVal |= function_namespace0_generated_706_finish(server, &nsMapping);
retVal |= function_namespace0_generated_705_finish(server, &nsMapping);
retVal |= function_namespace0_generated_704_finish(server, &nsMapping);
retVal |= function_namespace0_generated_703_finish(server, &nsMapping);
retVal |= function_namespace0_generated_702_finish(server, &nsMapping);
retVal |= function_namespace0_generated_701_finish(server, &nsMapping);
retVal |= function_namespace0_generated_700_finish(server, &nsMapping);
retVal |= function_namespace0_generated_699_finish(server, &nsMapping);
retVal |= function_namespace0_generated_698_finish(server, &nsMapping);
retVal |= function_namespace0_generated_697_finish(server, &nsMapping);
retVal |= function_namespace0_generated_696_finish(server, &nsMapping);
retVal |= function_namespace0_generated_695_finish(server, &nsMapping);
retVal |= function_namespace0_generated_694_finish(server, &nsMapping);
retVal |= function_namespace0_generated_693_finish(server, &nsMapping);
retVal |= function_namespace0_generated_692_finish(server, &nsMapping);
retVal |= function_namespace0_generated_691_finish(server, &nsMapping);
retVal |= function_namespace0_generated_690_finish(server, &nsMapping);
retVal |= function_namespace0_generated_689_finish(server, &nsMapping);
retVal |= function_namespace0_generated_688_finish(server, &nsMapping);
retVal |= function_namespace0_generated_687_finish(server, &nsMapping);
retVal |= function_namespace0_generated_686_finish(server, &nsMapping);
retVal |= function_namespace0_generated_685_finish(server, &nsMapping);
retVal |= function_namespace0_generated_684_finish(server, &nsMapping);
retVal |= function_namespace0_generated_683_finish(server, &nsMapping);
retVal |= function_namespace0_generated_682_finish(server, &nsMapping);
retVal |= function_namespace0_generated_681_finish(server, &nsMapping);
retVal |= function_namespace0_generated_680_finish(server, &nsMapping);
retVal |= function_namespace0_generated_679_finish(server, &nsMapping);
retVal |= function_namespace0_generated_678_finish(server, &nsMapping);
retVal |= function_namespace0_generated_677_finish(server, &nsMapping);
retVal |= function_namespace0_generated_676_finish(server, &nsMapping);
retVal |= function_namespace0_generated_675_finish(server, &nsMapping);
retVal |= function_namespace0_generated_674_finish(server, &nsMapping);
retVal |= function_namespace0_generated_673_finish(server, &nsMapping);
retVal |= function_namespace0_generated_672_finish(server, &nsMapping);
retVal |= function_namespace0_generated_671_finish(server, &nsMapping);
retVal |= function_namespace0_generated_670_finish(server, &nsMapping);
retVal |= function_namespace0_generated_669_finish(server, &nsMapping);
retVal |= function_namespace0_generated_668_finish(server, &nsMapping);
retVal |= function_namespace0_generated_667_finish(server, &nsMapping);
retVal |= function_namespace0_generated_666_finish(server, &nsMapping);
retVal |= function_namespace0_generated_665_finish(server, &nsMapping);
retVal |= function_namespace0_generated_664_finish(server, &nsMapping);
retVal |= function_namespace0_generated_663_finish(server, &nsMapping);
retVal |= function_namespace0_generated_662_finish(server, &nsMapping);
retVal |= function_namespace0_generated_661_finish(server, &nsMapping);
retVal |= function_namespace0_generated_660_finish(server, &nsMapping);
retVal |= function_namespace0_generated_659_finish(server, &nsMapping);
retVal |= function_namespace0_generated_658_finish(server, &nsMapping);
retVal |= function_namespace0_generated_657_finish(server, &nsMapping);
retVal |= function_namespace0_generated_656_finish(server, &nsMapping);
retVal |= function_namespace0_generated_655_finish(server, &nsMapping);
retVal |= function_namespace0_generated_654_finish(server, &nsMapping);
retVal |= function_namespace0_generated_653_finish(server, &nsMapping);
retVal |= function_namespace0_generated_652_finish(server, &nsMapping);
retVal |= function_namespace0_generated_651_finish(server, &nsMapping);
retVal |= function_namespace0_generated_650_finish(server, &nsMapping);
retVal |= function_namespace0_generated_649_finish(server, &nsMapping);
retVal |= function_namespace0_generated_648_finish(server, &nsMapping);
retVal |= function_namespace0_generated_647_finish(server, &nsMapping);
retVal |= function_namespace0_generated_646_finish(server, &nsMapping);
retVal |= function_namespace0_generated_645_finish(server, &nsMapping);
retVal |= function_namespace0_generated_644_finish(server, &nsMapping);
retVal |= function_namespace0_generated_643_finish(server, &nsMapping);
retVal |= function_namespace0_generated_642_finish(server, &nsMapping);
retVal |= function_namespace0_generated_641_finish(server, &nsMapping);
retVal |= function_namespace0_generated_640_finish(server, &nsMapping);
retVal |= function_namespace0_generated_639_finish(server, &nsMapping);
retVal |= function_namespace0_generated_638_finish(server, &nsMapping);
retVal |= function_namespace0_generated_637_finish(server, &nsMapping);
retVal |= function_namespace0_generated_636_finish(server, &nsMapping);
retVal |= function_namespace0_generated_635_finish(server, &nsMapping);
retVal |= function_namespace0_generated_634_finish(server, &nsMapping);
retVal |= function_namespace0_generated_633_finish(server, &nsMapping);
retVal |= function_namespace0_generated_632_finish(server, &nsMapping);
retVal |= function_namespace0_generated_631_finish(server, &nsMapping);
retVal |= function_namespace0_generated_630_finish(server, &nsMapping);
retVal |= function_namespace0_generated_629_finish(server, &nsMapping);
retVal |= function_namespace0_generated_628_finish(server, &nsMapping);
retVal |= function_namespace0_generated_627_finish(server, &nsMapping);
retVal |= function_namespace0_generated_626_finish(server, &nsMapping);
retVal |= function_namespace0_generated_625_finish(server, &nsMapping);
retVal |= function_namespace0_generated_624_finish(server, &nsMapping);
retVal |= function_namespace0_generated_623_finish(server, &nsMapping);
retVal |= function_namespace0_generated_622_finish(server, &nsMapping);
retVal |= function_namespace0_generated_621_finish(server, &nsMapping);
retVal |= function_namespace0_generated_620_finish(server, &nsMapping);
retVal |= function_namespace0_generated_619_finish(server, &nsMapping);
retVal |= function_namespace0_generated_618_finish(server, &nsMapping);
retVal |= function_namespace0_generated_617_finish(server, &nsMapping);
retVal |= function_namespace0_generated_616_finish(server, &nsMapping);
retVal |= function_namespace0_generated_615_finish(server, &nsMapping);
retVal |= function_namespace0_generated_614_finish(server, &nsMapping);
retVal |= function_namespace0_generated_613_finish(server, &nsMapping);
retVal |= function_namespace0_generated_612_finish(server, &nsMapping);
retVal |= function_namespace0_generated_611_finish(server, &nsMapping);
retVal |= function_namespace0_generated_610_finish(server, &nsMapping);
retVal |= function_namespace0_generated_609_finish(server, &nsMapping);
retVal |= function_namespace0_generated_608_finish(server, &nsMapping);
retVal |= function_namespace0_generated_607_finish(server, &nsMapping);
retVal |= function_namespace0_generated_606_finish(server, &nsMapping);
retVal |= function_namespace0_generated_605_finish(server, &nsMapping);
retVal |= function_namespace0_generated_604_finish(server, &nsMapping);
retVal |= function_namespace0_generated_603_finish(server, &nsMapping);
retVal |= function_namespace0_generated_602_finish(server, &nsMapping);
retVal |= function_namespace0_generated_601_finish(server, &nsMapping);
retVal |= function_namespace0_generated_600_finish(server, &nsMapping);
retVal |= function_namespace0_generated_599_finish(server, &nsMapping);
retVal |= function_namespace0_generated_598_finish(server, &nsMapping);
retVal |= function_namespace0_generated_597_finish(server, &nsMapping);
retVal |= function_namespace0_generated_596_finish(server, &nsMapping);
retVal |= function_namespace0_generated_595_finish(server, &nsMapping);
retVal |= function_namespace0_generated_594_finish(server, &nsMapping);
retVal |= function_namespace0_generated_593_finish(server, &nsMapping);
retVal |= function_namespace0_generated_592_finish(server, &nsMapping);
retVal |= function_namespace0_generated_591_finish(server, &nsMapping);
retVal |= function_namespace0_generated_590_finish(server, &nsMapping);
retVal |= function_namespace0_generated_589_finish(server, &nsMapping);
retVal |= function_namespace0_generated_588_finish(server, &nsMapping);
retVal |= function_namespace0_generated_587_finish(server, &nsMapping);
retVal |= function_namespace0_generated_586_finish(server, &nsMapping);
retVal |= function_namespace0_generated_585_finish(server, &nsMapping);
retVal |= function_namespace0_generated_584_finish(server, &nsMapping);
retVal |= function_namespace0_generated_583_finish(server, &nsMapping);
retVal |= function_namespace0_generated_582_finish(server, &nsMapping);
retVal |= function_namespace0_generated_581_finish(server, &nsMapping);
retVal |= function_namespace0_generated_580_finish(server, &nsMapping);
retVal |= function_namespace0_generated_579_finish(server, &nsMapping);
retVal |= function_namespace0_generated_578_finish(server, &nsMapping);
retVal |= function_namespace0_generated_577_finish(server, &nsMapping);
retVal |= function_namespace0_generated_576_finish(server, &nsMapping);
retVal |= function_namespace0_generated_575_finish(server, &nsMapping);
retVal |= function_namespace0_generated_574_finish(server, &nsMapping);
retVal |= function_namespace0_generated_573_finish(server, &nsMapping);
retVal |= function_namespace0_generated_572_finish(server, &nsMapping);
retVal |= function_namespace0_generated_571_finish(server, &nsMapping);
retVal |= function_namespace0_generated_570_finish(server, &nsMapping);
retVal |= function_namespace0_generated_569_finish(server, &nsMapping);
retVal |= function_namespace0_generated_568_finish(server, &nsMapping);
retVal |= function_namespace0_generated_567_finish(server, &nsMapping);
retVal |= function_namespace0_generated_566_finish(server, &nsMapping);
retVal |= function_namespace0_generated_565_finish(server, &nsMapping);
retVal |= function_namespace0_generated_564_finish(server, &nsMapping);
retVal |= function_namespace0_generated_563_finish(server, &nsMapping);
retVal |= function_namespace0_generated_562_finish(server, &nsMapping);
retVal |= function_namespace0_generated_561_finish(server, &nsMapping);
retVal |= function_namespace0_generated_560_finish(server, &nsMapping);
retVal |= function_namespace0_generated_559_finish(server, &nsMapping);
retVal |= function_namespace0_generated_558_finish(server, &nsMapping);
retVal |= function_namespace0_generated_557_finish(server, &nsMapping);
retVal |= function_namespace0_generated_556_finish(server, &nsMapping);
retVal |= function_namespace0_generated_555_finish(server, &nsMapping);
retVal |= function_namespace0_generated_554_finish(server, &nsMapping);
retVal |= function_namespace0_generated_553_finish(server, &nsMapping);
retVal |= function_namespace0_generated_552_finish(server, &nsMapping);
retVal |= function_namespace0_generated_551_finish(server, &nsMapping);
retVal |= function_namespace0_generated_550_finish(server, &nsMapping);
retVal |= function_namespace0_generated_549_finish(server, &nsMapping);
retVal |= function_namespace0_generated_548_finish(server, &nsMapping);
retVal |= function_namespace0_generated_547_finish(server, &nsMapping);
retVal |= function_namespace0_generated_546_finish(server, &nsMapping);
retVal |= function_namespace0_generated_545_finish(server, &nsMapping);
retVal |= function_namespace0_generated_544_finish(server, &nsMapping);
retVal |= function_namespace0_generated_543_finish(server, &nsMapping);
retVal |= function_namespace0_generated_542_finish(server, &nsMapping);
retVal |= function_namespace0_generated_541_finish(server, &nsMapping);
retVal |= function_namespace0_generated_540_finish(server, &nsMapping);
retVal |= function_namespace0_generated_539_finish(server, &nsMapping);
retVal |= function_namespace0_generated_538_finish(server, &nsMapping);
retVal |= function_namespace0_generated_537_finish(server, &nsMapping);
retVal |= function_namespace0_generated_536_finish(server, &nsMapping);
retVal |= function_namespace0_generated_535_finish(server, &nsMapping);
retVal |= function_namespace0_generated_534_finish(server, &nsMapping);
retVal |= function_namespace0_generated_533_finish(server, &nsMapping);
retVal |= function_namespace0_generated_532_finish(server, &nsMapping);
retVal |= function_namespace0_generated_531_finish(server, &nsMapping);
retVal |= function_namespace0_generated_530_finish(server, &nsMapping);
retVal |= function_namespace0_generated_529_finish(server, &nsMapping);
retVal |= function_namespace0_generated_528_finish(server, &nsMapping);
retVal |= function_namespace0_generated_527_finish(server, &nsMapping);
retVal |= function_namespace0_generated_526_finish(server, &nsMapping);
retVal |= function_namespace0_generated_525_finish(server, &nsMapping);
retVal |= function_namespace0_generated_524_finish(server, &nsMapping);
retVal |= function_namespace0_generated_523_finish(server, &nsMapping);
retVal |= function_namespace0_generated_522_finish(server, &nsMapping);
retVal |= function_namespace0_generated_521_finish(server, &nsMapping);
retVal |= function_namespace0_generated_520_finish(server, &nsMapping);
retVal |= function_namespace0_generated_519_finish(server, &nsMapping);
retVal |= function_namespace0_generated_518_finish(server, &nsMapping);
retVal |= function_namespace0_generated_517_finish(server, &nsMapping);
retVal |= function_namespace0_generated_516_finish(server, &nsMapping);
retVal |= function_namespace0_generated_515_finish(server, &nsMapping);
retVal |= function_namespace0_generated_514_finish(server, &nsMapping);
retVal |= function_namespace0_generated_513_finish(server, &nsMapping);
retVal |= function_namespace0_generated_512_finish(server, &nsMapping);
retVal |= function_namespace0_generated_511_finish(server, &nsMapping);
retVal |= function_namespace0_generated_510_finish(server, &nsMapping);
retVal |= function_namespace0_generated_509_finish(server, &nsMapping);
retVal |= function_namespace0_generated_508_finish(server, &nsMapping);
retVal |= function_namespace0_generated_507_finish(server, &nsMapping);
retVal |= function_namespace0_generated_506_finish(server, &nsMapping);
retVal |= function_namespace0_generated_505_finish(server, &nsMapping);
retVal |= function_namespace0_generated_504_finish(server, &nsMapping);
retVal |= function_namespace0_generated_503_finish(server, &nsMapping);
retVal |= function_namespace0_generated_502_finish(server, &nsMapping);
retVal |= function_namespace0_generated_501_finish(server, &nsMapping);
retVal |= function_namespace0_generated_500_finish(server, &nsMapping);
retVal |= function_namespace0_generated_499_finish(server, &nsMapping);
retVal |= function_namespace0_generated_498_finish(server, &nsMapping);
retVal |= function_namespace0_generated_497_finish(server, &nsMapping);
retVal |= function_namespace0_generated_496_finish(server, &nsMapping);
retVal |= function_namespace0_generated_495_finish(server, &nsMapping);
retVal |= function_namespace0_generated_494_finish(server, &nsMapping);
retVal |= function_namespace0_generated_493_finish(server, &nsMapping);
retVal |= function_namespace0_generated_492_finish(server, &nsMapping);
retVal |= function_namespace0_generated_491_finish(server, &nsMapping);
retVal |= function_namespace0_generated_490_finish(server, &nsMapping);
retVal |= function_namespace0_generated_489_finish(server, &nsMapping);
retVal |= function_namespace0_generated_488_finish(server, &nsMapping);
retVal |= function_namespace0_generated_487_finish(server, &nsMapping);
retVal |= function_namespace0_generated_486_finish(server, &nsMapping);
retVal |= function_namespace0_generated_485_finish(server, &nsMapping);
retVal |= function_namespace0_generated_484_finish(server, &nsMapping);
retVal |= function_namespace0_generated_483_finish(server, &nsMapping);
retVal |= function_namespace0_generated_482_finish(server, &nsMapping);
retVal |= function_namespace0_generated_481_finish(server, &nsMapping);
retVal |= function_namespace0_generated_480_finish(server, &nsMapping);
retVal |= function_namespace0_generated_479_finish(server, &nsMapping);
retVal |= function_namespace0_generated_478_finish(server, &nsMapping);
retVal |= function_namespace0_generated_477_finish(server, &nsMapping);
retVal |= function_namespace0_generated_476_finish(server, &nsMapping);
retVal |= function_namespace0_generated_475_finish(server, &nsMapping);
retVal |= function_namespace0_generated_474_finish(server, &nsMapping);
retVal |= function_namespace0_generated_473_finish(server, &nsMapping);
retVal |= function_namespace0_generated_472_finish(server, &nsMapping);
retVal |= function_namespace0_generated_471_finish(server, &nsMapping);
retVal |= function_namespace0_generated_470_finish(server, &nsMapping);
retVal |= function_namespace0_generated_469_finish(server, &nsMapping);
retVal |= function_namespace0_generated_468_finish(server, &nsMapping);
retVal |= function_namespace0_generated_467_finish(server, &nsMapping);
retVal |= function_namespace0_generated_466_finish(server, &nsMapping);
retVal |= function_namespace0_generated_465_finish(server, &nsMapping);
retVal |= function_namespace0_generated_464_finish(server, &nsMapping);
retVal |= function_namespace0_generated_463_finish(server, &nsMapping);
retVal |= function_namespace0_generated_462_finish(server, &nsMapping);
retVal |= function_namespace0_generated_461_finish(server, &nsMapping);
retVal |= function_namespace0_generated_460_finish(server, &nsMapping);
retVal |= function_namespace0_generated_459_finish(server, &nsMapping);
retVal |= function_namespace0_generated_458_finish(server, &nsMapping);
retVal |= function_namespace0_generated_457_finish(server, &nsMapping);
retVal |= function_namespace0_generated_456_finish(server, &nsMapping);
retVal |= function_namespace0_generated_455_finish(server, &nsMapping);
retVal |= function_namespace0_generated_454_finish(server, &nsMapping);
retVal |= function_namespace0_generated_453_finish(server, &nsMapping);
retVal |= function_namespace0_generated_452_finish(server, &nsMapping);
retVal |= function_namespace0_generated_451_finish(server, &nsMapping);
retVal |= function_namespace0_generated_450_finish(server, &nsMapping);
retVal |= function_namespace0_generated_449_finish(server, &nsMapping);
retVal |= function_namespace0_generated_448_finish(server, &nsMapping);
retVal |= function_namespace0_generated_447_finish(server, &nsMapping);
retVal |= function_namespace0_generated_446_finish(server, &nsMapping);
retVal |= function_namespace0_generated_445_finish(server, &nsMapping);
retVal |= function_namespace0_generated_444_finish(server, &nsMapping);
retVal |= function_namespace0_generated_443_finish(server, &nsMapping);
retVal |= function_namespace0_generated_442_finish(server, &nsMapping);
retVal |= function_namespace0_generated_441_finish(server, &nsMapping);
retVal |= function_namespace0_generated_440_finish(server, &nsMapping);
retVal |= function_namespace0_generated_439_finish(server, &nsMapping);
retVal |= function_namespace0_generated_438_finish(server, &nsMapping);
retVal |= function_namespace0_generated_437_finish(server, &nsMapping);
retVal |= function_namespace0_generated_436_finish(server, &nsMapping);
retVal |= function_namespace0_generated_435_finish(server, &nsMapping);
retVal |= function_namespace0_generated_434_finish(server, &nsMapping);
retVal |= function_namespace0_generated_433_finish(server, &nsMapping);
retVal |= function_namespace0_generated_432_finish(server, &nsMapping);
retVal |= function_namespace0_generated_431_finish(server, &nsMapping);
retVal |= function_namespace0_generated_430_finish(server, &nsMapping);
retVal |= function_namespace0_generated_429_finish(server, &nsMapping);
retVal |= function_namespace0_generated_428_finish(server, &nsMapping);
retVal |= function_namespace0_generated_427_finish(server, &nsMapping);
retVal |= function_namespace0_generated_426_finish(server, &nsMapping);
retVal |= function_namespace0_generated_425_finish(server, &nsMapping);
retVal |= function_namespace0_generated_424_finish(server, &nsMapping);
retVal |= function_namespace0_generated_423_finish(server, &nsMapping);
retVal |= function_namespace0_generated_422_finish(server, &nsMapping);
retVal |= function_namespace0_generated_421_finish(server, &nsMapping);
retVal |= function_namespace0_generated_420_finish(server, &nsMapping);
retVal |= function_namespace0_generated_419_finish(server, &nsMapping);
retVal |= function_namespace0_generated_418_finish(server, &nsMapping);
retVal |= function_namespace0_generated_417_finish(server, &nsMapping);
retVal |= function_namespace0_generated_416_finish(server, &nsMapping);
retVal |= function_namespace0_generated_415_finish(server, &nsMapping);
retVal |= function_namespace0_generated_414_finish(server, &nsMapping);
retVal |= function_namespace0_generated_413_finish(server, &nsMapping);
retVal |= function_namespace0_generated_412_finish(server, &nsMapping);
retVal |= function_namespace0_generated_411_finish(server, &nsMapping);
retVal |= function_namespace0_generated_410_finish(server, &nsMapping);
retVal |= function_namespace0_generated_409_finish(server, &nsMapping);
retVal |= function_namespace0_generated_408_finish(server, &nsMapping);
retVal |= function_namespace0_generated_407_finish(server, &nsMapping);
retVal |= function_namespace0_generated_406_finish(server, &nsMapping);
retVal |= function_namespace0_generated_405_finish(server, &nsMapping);
retVal |= function_namespace0_generated_404_finish(server, &nsMapping);
retVal |= function_namespace0_generated_403_finish(server, &nsMapping);
retVal |= function_namespace0_generated_402_finish(server, &nsMapping);
retVal |= function_namespace0_generated_401_finish(server, &nsMapping);
retVal |= function_namespace0_generated_400_finish(server, &nsMapping);
retVal |= function_namespace0_generated_399_finish(server, &nsMapping);
retVal |= function_namespace0_generated_398_finish(server, &nsMapping);
retVal |= function_namespace0_generated_397_finish(server, &nsMapping);
retVal |= function_namespace0_generated_396_finish(server, &nsMapping);
retVal |= function_namespace0_generated_395_finish(server, &nsMapping);
retVal |= function_namespace0_generated_394_finish(server, &nsMapping);
retVal |= function_namespace0_generated_393_finish(server, &nsMapping);
retVal |= function_namespace0_generated_392_finish(server, &nsMapping);
retVal |= function_namespace0_generated_391_finish(server, &nsMapping);
retVal |= function_namespace0_generated_390_finish(server, &nsMapping);
retVal |= function_namespace0_generated_389_finish(server, &nsMapping);
retVal |= function_namespace0_generated_388_finish(server, &nsMapping);
retVal |= function_namespace0_generated_387_finish(server, &nsMapping);
retVal |= function_namespace0_generated_386_finish(server, &nsMapping);
retVal |= function_namespace0_generated_385_finish(server, &nsMapping);
retVal |= function_namespace0_generated_384_finish(server, &nsMapping);
retVal |= function_namespace0_generated_383_finish(server, &nsMapping);
retVal |= function_namespace0_generated_382_finish(server, &nsMapping);
retVal |= function_namespace0_generated_381_finish(server, &nsMapping);
retVal |= function_namespace0_generated_380_finish(server, &nsMapping);
retVal |= function_namespace0_generated_379_finish(server, &nsMapping);
retVal |= function_namespace0_generated_378_finish(server, &nsMapping);
retVal |= function_namespace0_generated_377_finish(server, &nsMapping);
retVal |= function_namespace0_generated_376_finish(server, &nsMapping);
retVal |= function_namespace0_generated_375_finish(server, &nsMapping);
retVal |= function_namespace0_generated_374_finish(server, &nsMapping);
retVal |= function_namespace0_generated_373_finish(server, &nsMapping);
retVal |= function_namespace0_generated_372_finish(server, &nsMapping);
retVal |= function_namespace0_generated_371_finish(server, &nsMapping);
retVal |= function_namespace0_generated_370_finish(server, &nsMapping);
retVal |= function_namespace0_generated_369_finish(server, &nsMapping);
retVal |= function_namespace0_generated_368_finish(server, &nsMapping);
retVal |= function_namespace0_generated_367_finish(server, &nsMapping);
retVal |= function_namespace0_generated_366_finish(server, &nsMapping);
retVal |= function_namespace0_generated_365_finish(server, &nsMapping);
retVal |= function_namespace0_generated_364_finish(server, &nsMapping);
retVal |= function_namespace0_generated_363_finish(server, &nsMapping);
retVal |= function_namespace0_generated_362_finish(server, &nsMapping);
retVal |= function_namespace0_generated_361_finish(server, &nsMapping);
retVal |= function_namespace0_generated_360_finish(server, &nsMapping);
retVal |= function_namespace0_generated_359_finish(server, &nsMapping);
retVal |= function_namespace0_generated_358_finish(server, &nsMapping);
retVal |= function_namespace0_generated_357_finish(server, &nsMapping);
retVal |= function_namespace0_generated_356_finish(server, &nsMapping);
retVal |= function_namespace0_generated_355_finish(server, &nsMapping);
retVal |= function_namespace0_generated_354_finish(server, &nsMapping);
retVal |= function_namespace0_generated_353_finish(server, &nsMapping);
retVal |= function_namespace0_generated_352_finish(server, &nsMapping);
retVal |= function_namespace0_generated_351_finish(server, &nsMapping);
retVal |= function_namespace0_generated_350_finish(server, &nsMapping);
retVal |= function_namespace0_generated_349_finish(server, &nsMapping);
retVal |= function_namespace0_generated_348_finish(server, &nsMapping);
retVal |= function_namespace0_generated_347_finish(server, &nsMapping);
retVal |= function_namespace0_generated_346_finish(server, &nsMapping);
retVal |= function_namespace0_generated_345_finish(server, &nsMapping);
retVal |= function_namespace0_generated_344_finish(server, &nsMapping);
retVal |= function_namespace0_generated_343_finish(server, &nsMapping);
retVal |= function_namespace0_generated_342_finish(server, &nsMapping);
retVal |= function_namespace0_generated_341_finish(server, &nsMapping);
retVal |= function_namespace0_generated_340_finish(server, &nsMapping);
retVal |= function_namespace0_generated_339_finish(server, &nsMapping);
retVal |= function_namespace0_generated_338_finish(server, &nsMapping);
retVal |= function_namespace0_generated_337_finish(server, &nsMapping);
retVal |= function_namespace0_generated_336_finish(server, &nsMapping);
retVal |= function_namespace0_generated_335_finish(server, &nsMapping);
retVal |= function_namespace0_generated_334_finish(server, &nsMapping);
retVal |= function_namespace0_generated_333_finish(server, &nsMapping);
retVal |= function_namespace0_generated_332_finish(server, &nsMapping);
retVal |= function_namespace0_generated_331_finish(server, &nsMapping);
retVal |= function_namespace0_generated_330_finish(server, &nsMapping);
retVal |= function_namespace0_generated_329_finish(server, &nsMapping);
retVal |= function_namespace0_generated_328_finish(server, &nsMapping);
retVal |= function_namespace0_generated_327_finish(server, &nsMapping);
retVal |= function_namespace0_generated_326_finish(server, &nsMapping);
retVal |= function_namespace0_generated_325_finish(server, &nsMapping);
retVal |= function_namespace0_generated_324_finish(server, &nsMapping);
retVal |= function_namespace0_generated_323_finish(server, &nsMapping);
retVal |= function_namespace0_generated_322_finish(server, &nsMapping);
retVal |= function_namespace0_generated_321_finish(server, &nsMapping);
retVal |= function_namespace0_generated_320_finish(server, &nsMapping);
retVal |= function_namespace0_generated_319_finish(server, &nsMapping);
retVal |= function_namespace0_generated_318_finish(server, &nsMapping);
retVal |= function_namespace0_generated_317_finish(server, &nsMapping);
retVal |= function_namespace0_generated_316_finish(server, &nsMapping);
retVal |= function_namespace0_generated_315_finish(server, &nsMapping);
retVal |= function_namespace0_generated_314_finish(server, &nsMapping);
retVal |= function_namespace0_generated_313_finish(server, &nsMapping);
retVal |= function_namespace0_generated_312_finish(server, &nsMapping);
retVal |= function_namespace0_generated_311_finish(server, &nsMapping);
retVal |= function_namespace0_generated_310_finish(server, &nsMapping);
retVal |= function_namespace0_generated_309_finish(server, &nsMapping);
retVal |= function_namespace0_generated_308_finish(server, &nsMapping);
retVal |= function_namespace0_generated_307_finish(server, &nsMapping);
retVal |= function_namespace0_generated_306_finish(server, &nsMapping);
retVal |= function_namespace0_generated_305_finish(server, &nsMapping);
retVal |= function_namespace0_generated_304_finish(server, &nsMapping);
retVal |= function_namespace0_generated_303_finish(server, &nsMapping);
retVal |= function_namespace0_generated_302_finish(server, &nsMapping);
retVal |= function_namespace0_generated_301_finish(server, &nsMapping);
retVal |= function_namespace0_generated_300_finish(server, &nsMapping);
retVal |= function_namespace0_generated_299_finish(server, &nsMapping);
retVal |= function_namespace0_generated_298_finish(server, &nsMapping);
retVal |= function_namespace0_generated_297_finish(server, &nsMapping);
retVal |= function_namespace0_generated_296_finish(server, &nsMapping);
retVal |= function_namespace0_generated_295_finish(server, &nsMapping);
retVal |= function_namespace0_generated_294_finish(server, &nsMapping);
retVal |= function_namespace0_generated_293_finish(server, &nsMapping);
retVal |= function_namespace0_generated_292_finish(server, &nsMapping);
retVal |= function_namespace0_generated_291_finish(server, &nsMapping);
retVal |= function_namespace0_generated_290_finish(server, &nsMapping);
retVal |= function_namespace0_generated_289_finish(server, &nsMapping);
retVal |= function_namespace0_generated_288_finish(server, &nsMapping);
retVal |= function_namespace0_generated_287_finish(server, &nsMapping);
retVal |= function_namespace0_generated_286_finish(server, &nsMapping);
retVal |= function_namespace0_generated_285_finish(server, &nsMapping);
retVal |= function_namespace0_generated_284_finish(server, &nsMapping);
retVal |= function_namespace0_generated_283_finish(server, &nsMapping);
retVal |= function_namespace0_generated_282_finish(server, &nsMapping);
retVal |= function_namespace0_generated_281_finish(server, &nsMapping);
retVal |= function_namespace0_generated_280_finish(server, &nsMapping);
retVal |= function_namespace0_generated_279_finish(server, &nsMapping);
retVal |= function_namespace0_generated_278_finish(server, &nsMapping);
retVal |= function_namespace0_generated_277_finish(server, &nsMapping);
retVal |= function_namespace0_generated_276_finish(server, &nsMapping);
retVal |= function_namespace0_generated_275_finish(server, &nsMapping);
retVal |= function_namespace0_generated_274_finish(server, &nsMapping);
retVal |= function_namespace0_generated_273_finish(server, &nsMapping);
retVal |= function_namespace0_generated_272_finish(server, &nsMapping);
retVal |= function_namespace0_generated_271_finish(server, &nsMapping);
retVal |= function_namespace0_generated_270_finish(server, &nsMapping);
retVal |= function_namespace0_generated_269_finish(server, &nsMapping);
retVal |= function_namespace0_generated_268_finish(server, &nsMapping);
retVal |= function_namespace0_generated_267_finish(server, &nsMapping);
retVal |= function_namespace0_generated_266_finish(server, &nsMapping);
retVal |= function_namespace0_generated_265_finish(server, &nsMapping);
retVal |= function_namespace0_generated_264_finish(server, &nsMapping);
retVal |= function_namespace0_generated_263_finish(server, &nsMapping);
retVal |= function_namespace0_generated_262_finish(server, &nsMapping);
retVal |= function_namespace0_generated_261_finish(server, &nsMapping);
retVal |= function_namespace0_generated_260_finish(server, &nsMapping);
retVal |= function_namespace0_generated_259_finish(server, &nsMapping);
retVal |= function_namespace0_generated_258_finish(server, &nsMapping);
retVal |= function_namespace0_generated_257_finish(server, &nsMapping);
retVal |= function_namespace0_generated_256_finish(server, &nsMapping);
retVal |= function_namespace0_generated_255_finish(server, &nsMapping);
retVal |= function_namespace0_generated_254_finish(server, &nsMapping);
retVal |= function_namespace0_generated_253_finish(server, &nsMapping);
retVal |= function_namespace0_generated_252_finish(server, &nsMapping);
retVal |= function_namespace0_generated_251_finish(server, &nsMapping);
retVal |= function_namespace0_generated_250_finish(server, &nsMapping);
retVal |= function_namespace0_generated_249_finish(server, &nsMapping);
retVal |= function_namespace0_generated_248_finish(server, &nsMapping);
retVal |= function_namespace0_generated_247_finish(server, &nsMapping);
retVal |= function_namespace0_generated_246_finish(server, &nsMapping);
retVal |= function_namespace0_generated_245_finish(server, &nsMapping);
retVal |= function_namespace0_generated_244_finish(server, &nsMapping);
retVal |= function_namespace0_generated_243_finish(server, &nsMapping);
retVal |= function_namespace0_generated_242_finish(server, &nsMapping);
retVal |= function_namespace0_generated_241_finish(server, &nsMapping);
retVal |= function_namespace0_generated_240_finish(server, &nsMapping);
retVal |= function_namespace0_generated_239_finish(server, &nsMapping);
retVal |= function_namespace0_generated_238_finish(server, &nsMapping);
retVal |= function_namespace0_generated_237_finish(server, &nsMapping);
retVal |= function_namespace0_generated_236_finish(server, &nsMapping);
retVal |= function_namespace0_generated_235_finish(server, &nsMapping);
retVal |= function_namespace0_generated_234_finish(server, &nsMapping);
retVal |= function_namespace0_generated_233_finish(server, &nsMapping);
retVal |= function_namespace0_generated_232_finish(server, &nsMapping);
retVal |= function_namespace0_generated_231_finish(server, &nsMapping);
retVal |= function_namespace0_generated_230_finish(server, &nsMapping);
retVal |= function_namespace0_generated_229_finish(server, &nsMapping);
retVal |= function_namespace0_generated_228_finish(server, &nsMapping);
retVal |= function_namespace0_generated_227_finish(server, &nsMapping);
retVal |= function_namespace0_generated_226_finish(server, &nsMapping);
retVal |= function_namespace0_generated_225_finish(server, &nsMapping);
retVal |= function_namespace0_generated_224_finish(server, &nsMapping);
retVal |= function_namespace0_generated_223_finish(server, &nsMapping);
retVal |= function_namespace0_generated_222_finish(server, &nsMapping);
retVal |= function_namespace0_generated_221_finish(server, &nsMapping);
retVal |= function_namespace0_generated_220_finish(server, &nsMapping);
retVal |= function_namespace0_generated_219_finish(server, &nsMapping);
retVal |= function_namespace0_generated_218_finish(server, &nsMapping);
retVal |= function_namespace0_generated_217_finish(server, &nsMapping);
retVal |= function_namespace0_generated_216_finish(server, &nsMapping);
retVal |= function_namespace0_generated_215_finish(server, &nsMapping);
retVal |= function_namespace0_generated_214_finish(server, &nsMapping);
retVal |= function_namespace0_generated_213_finish(server, &nsMapping);
retVal |= function_namespace0_generated_212_finish(server, &nsMapping);
retVal |= function_namespace0_generated_211_finish(server, &nsMapping);
retVal |= function_namespace0_generated_210_finish(server, &nsMapping);
retVal |= function_namespace0_generated_209_finish(server, &nsMapping);
retVal |= function_namespace0_generated_208_finish(server, &nsMapping);
retVal |= function_namespace0_generated_207_finish(server, &nsMapping);
retVal |= function_namespace0_generated_206_finish(server, &nsMapping);
retVal |= function_namespace0_generated_205_finish(server, &nsMapping);
retVal |= function_namespace0_generated_204_finish(server, &nsMapping);
retVal |= function_namespace0_generated_203_finish(server, &nsMapping);
retVal |= function_namespace0_generated_202_finish(server, &nsMapping);
retVal |= function_namespace0_generated_201_finish(server, &nsMapping);
retVal |= function_namespace0_generated_200_finish(server, &nsMapping);
retVal |= function_namespace0_generated_199_finish(server, &nsMapping);
retVal |= function_namespace0_generated_198_finish(server, &nsMapping);
retVal |= function_namespace0_generated_197_finish(server, &nsMapping);
retVal |= function_namespace0_generated_196_finish(server, &nsMapping);
retVal |= function_namespace0_generated_195_finish(server, &nsMapping);
retVal |= function_namespace0_generated_194_finish(server, &nsMapping);
retVal |= function_namespace0_generated_193_finish(server, &nsMapping);
retVal |= function_namespace0_generated_192_finish(server, &nsMapping);
retVal |= function_namespace0_generated_191_finish(server, &nsMapping);
retVal |= function_namespace0_generated_190_finish(server, &nsMapping);
retVal |= function_namespace0_generated_189_finish(server, &nsMapping);
retVal |= function_namespace0_generated_188_finish(server, &nsMapping);
retVal |= function_namespace0_generated_187_finish(server, &nsMapping);
retVal |= function_namespace0_generated_186_finish(server, &nsMapping);
retVal |= function_namespace0_generated_185_finish(server, &nsMapping);
retVal |= function_namespace0_generated_184_finish(server, &nsMapping);
retVal |= function_namespace0_generated_183_finish(server, &nsMapping);
retVal |= function_namespace0_generated_182_finish(server, &nsMapping);
retVal |= function_namespace0_generated_181_finish(server, &nsMapping);
retVal |= function_namespace0_generated_180_finish(server, &nsMapping);
retVal |= function_namespace0_generated_179_finish(server, &nsMapping);
retVal |= function_namespace0_generated_178_finish(server, &nsMapping);
retVal |= function_namespace0_generated_177_finish(server, &nsMapping);
retVal |= function_namespace0_generated_176_finish(server, &nsMapping);
retVal |= function_namespace0_generated_175_finish(server, &nsMapping);
retVal |= function_namespace0_generated_174_finish(server, &nsMapping);
retVal |= function_namespace0_generated_173_finish(server, &nsMapping);
retVal |= function_namespace0_generated_172_finish(server, &nsMapping);
retVal |= function_namespace0_generated_171_finish(server, &nsMapping);
retVal |= function_namespace0_generated_170_finish(server, &nsMapping);
retVal |= function_namespace0_generated_169_finish(server, &nsMapping);
retVal |= function_namespace0_generated_168_finish(server, &nsMapping);
retVal |= function_namespace0_generated_167_finish(server, &nsMapping);
retVal |= function_namespace0_generated_166_finish(server, &nsMapping);
retVal |= function_namespace0_generated_165_finish(server, &nsMapping);
retVal |= function_namespace0_generated_164_finish(server, &nsMapping);
retVal |= function_namespace0_generated_163_finish(server, &nsMapping);
retVal |= function_namespace0_generated_162_finish(server, &nsMapping);
retVal |= function_namespace0_generated_161_finish(server, &nsMapping);
retVal |= function_namespace0_generated_160_finish(server, &nsMapping);
retVal |= function_namespace0_generated_159_finish(server, &nsMapping);
retVal |= function_namespace0_generated_158_finish(server, &nsMapping);
retVal |= function_namespace0_generated_157_finish(server, &nsMapping);
retVal |= function_namespace0_generated_156_finish(server, &nsMapping);
retVal |= function_namespace0_generated_155_finish(server, &nsMapping);
retVal |= function_namespace0_generated_154_finish(server, &nsMapping);
retVal |= function_namespace0_generated_153_finish(server, &nsMapping);
retVal |= function_namespace0_generated_152_finish(server, &nsMapping);
retVal |= function_namespace0_generated_151_finish(server, &nsMapping);
retVal |= function_namespace0_generated_150_finish(server, &nsMapping);
retVal |= function_namespace0_generated_149_finish(server, &nsMapping);
retVal |= function_namespace0_generated_148_finish(server, &nsMapping);
retVal |= function_namespace0_generated_147_finish(server, &nsMapping);
retVal |= function_namespace0_generated_146_finish(server, &nsMapping);
retVal |= function_namespace0_generated_145_finish(server, &nsMapping);
retVal |= function_namespace0_generated_144_finish(server, &nsMapping);
retVal |= function_namespace0_generated_143_finish(server, &nsMapping);
retVal |= function_namespace0_generated_142_finish(server, &nsMapping);
retVal |= function_namespace0_generated_141_finish(server, &nsMapping);
retVal |= function_namespace0_generated_140_finish(server, &nsMapping);
retVal |= function_namespace0_generated_139_finish(server, &nsMapping);
retVal |= function_namespace0_generated_138_finish(server, &nsMapping);
retVal |= function_namespace0_generated_137_finish(server, &nsMapping);
retVal |= function_namespace0_generated_136_finish(server, &nsMapping);
retVal |= function_namespace0_generated_135_finish(server, &nsMapping);
retVal |= function_namespace0_generated_134_finish(server, &nsMapping);
retVal |= function_namespace0_generated_133_finish(server, &nsMapping);
retVal |= function_namespace0_generated_132_finish(server, &nsMapping);
retVal |= function_namespace0_generated_131_finish(server, &nsMapping);
retVal |= function_namespace0_generated_130_finish(server, &nsMapping);
retVal |= function_namespace0_generated_129_finish(server, &nsMapping);
retVal |= function_namespace0_generated_128_finish(server, &nsMapping);
retVal |= function_namespace0_generated_127_finish(server, &nsMapping);
retVal |= function_namespace0_generated_126_finish(server, &nsMapping);
retVal |= function_namespace0_generated_125_finish(server, &nsMapping);
retVal |= function_namespace0_generated_124_finish(server, &nsMapping);
retVal |= function_namespace0_generated_123_finish(server, &nsMapping);
retVal |= function_namespace0_generated_122_finish(server, &nsMapping);
retVal |= function_namespace0_generated_121_finish(server, &nsMapping);
retVal |= function_namespace0_generated_120_finish(server, &nsMapping);
retVal |= function_namespace0_generated_119_finish(server, &nsMapping);
retVal |= function_namespace0_generated_118_finish(server, &nsMapping);
retVal |= function_namespace0_generated_117_finish(server, &nsMapping);
retVal |= function_namespace0_generated_116_finish(server, &nsMapping);
retVal |= function_namespace0_generated_115_finish(server, &nsMapping);
retVal |= function_namespace0_generated_114_finish(server, &nsMapping);
retVal |= function_namespace0_generated_113_finish(server, &nsMapping);
retVal |= function_namespace0_generated_112_finish(server, &nsMapping);
retVal |= function_namespace0_generated_111_finish(server, &nsMapping);
retVal |= function_namespace0_generated_110_finish(server, &nsMapping);
retVal |= function_namespace0_generated_109_finish(server, &nsMapping);
retVal |= function_namespace0_generated_108_finish(server, &nsMapping);
retVal |= function_namespace0_generated_107_finish(server, &nsMapping);
retVal |= function_namespace0_generated_106_finish(server, &nsMapping);
retVal |= function_namespace0_generated_105_finish(server, &nsMapping);
retVal |= function_namespace0_generated_104_finish(server, &nsMapping);
retVal |= function_namespace0_generated_103_finish(server, &nsMapping);
retVal |= function_namespace0_generated_102_finish(server, &nsMapping);
retVal |= function_namespace0_generated_101_finish(server, &nsMapping);
retVal |= function_namespace0_generated_100_finish(server, &nsMapping);
retVal |= function_namespace0_generated_99_finish(server, &nsMapping);
retVal |= function_namespace0_generated_98_finish(server, &nsMapping);
retVal |= function_namespace0_generated_97_finish(server, &nsMapping);
retVal |= function_namespace0_generated_96_finish(server, &nsMapping);
retVal |= function_namespace0_generated_95_finish(server, &nsMapping);
retVal |= function_namespace0_generated_94_finish(server, &nsMapping);
retVal |= function_namespace0_generated_93_finish(server, &nsMapping);
retVal |= function_namespace0_generated_92_finish(server, &nsMapping);
retVal |= function_namespace0_generated_91_finish(server, &nsMapping);
retVal |= function_namespace0_generated_90_finish(server, &nsMapping);
retVal |= function_namespace0_generated_89_finish(server, &nsMapping);
retVal |= function_namespace0_generated_88_finish(server, &nsMapping);
retVal |= function_namespace0_generated_87_finish(server, &nsMapping);
retVal |= function_namespace0_generated_86_finish(server, &nsMapping);
retVal |= function_namespace0_generated_85_finish(server, &nsMapping);
retVal |= function_namespace0_generated_84_finish(server, &nsMapping);
retVal |= function_namespace0_generated_83_finish(server, &nsMapping);
retVal |= function_namespace0_generated_82_finish(server, &nsMapping);
retVal |= function_namespace0_generated_81_finish(server, &nsMapping);
retVal |= function_namespace0_generated_80_finish(server, &nsMapping);
retVal |= function_namespace0_generated_79_finish(server, &nsMapping);
retVal |= function_namespace0_generated_78_finish(server, &nsMapping);
retVal |= function_namespace0_generated_77_finish(server, &nsMapping);
retVal |= function_namespace0_generated_76_finish(server, &nsMapping);
retVal |= function_namespace0_generated_75_finish(server, &nsMapping);
retVal |= function_namespace0_generated_74_finish(server, &nsMapping);
retVal |= function_namespace0_generated_73_finish(server, &nsMapping);
retVal |= function_namespace0_generated_72_finish(server, &nsMapping);
retVal |= function_namespace0_generated_71_finish(server, &nsMapping);
retVal |= function_namespace0_generated_70_finish(server, &nsMapping);
retVal |= function_namespace0_generated_69_finish(server, &nsMapping);
retVal |= function_namespace0_generated_68_finish(server, &nsMapping);
retVal |= function_namespace0_generated_67_finish(server, &nsMapping);
retVal |= function_namespace0_generated_66_finish(server, &nsMapping);
retVal |= function_namespace0_generated_65_finish(server, &nsMapping);
retVal |= function_namespace0_generated_64_finish(server, &nsMapping);
retVal |= function_namespace0_generated_63_finish(server, &nsMapping);
retVal |= function_namespace0_generated_62_finish(server, &nsMapping);
retVal |= function_namespace0_generated_61_finish(server, &nsMapping);
retVal |= function_namespace0_generated_60_finish(server, &nsMapping);
retVal |= function_namespace0_generated_59_finish(server, &nsMapping);
retVal |= function_namespace0_generated_58_finish(server, &nsMapping);
retVal |= function_namespace0_generated_57_finish(server, &nsMapping);
retVal |= function_namespace0_generated_56_finish(server, &nsMapping);
retVal |= function_namespace0_generated_55_finish(server, &nsMapping);
retVal |= function_namespace0_generated_54_finish(server, &nsMapping);
retVal |= function_namespace0_generated_53_finish(server, &nsMapping);
retVal |= function_namespace0_generated_52_finish(server, &nsMapping);
retVal |= function_namespace0_generated_51_finish(server, &nsMapping);
retVal |= function_namespace0_generated_50_finish(server, &nsMapping);
retVal |= function_namespace0_generated_49_finish(server, &nsMapping);
retVal |= function_namespace0_generated_48_finish(server, &nsMapping);
retVal |= function_namespace0_generated_47_finish(server, &nsMapping);
retVal |= function_namespace0_generated_46_finish(server, &nsMapping);
retVal |= function_namespace0_generated_45_finish(server, &nsMapping);
retVal |= function_namespace0_generated_44_finish(server, &nsMapping);
retVal |= function_namespace0_generated_43_finish(server, &nsMapping);
retVal |= function_namespace0_generated_42_finish(server, &nsMapping);
retVal |= function_namespace0_generated_41_finish(server, &nsMapping);
retVal |= function_namespace0_generated_40_finish(server, &nsMapping);
retVal |= function_namespace0_generated_39_finish(server, &nsMapping);
retVal |= function_namespace0_generated_38_finish(server, &nsMapping);
retVal |= function_namespace0_generated_37_finish(server, &nsMapping);
retVal |= function_namespace0_generated_36_finish(server, &nsMapping);
retVal |= function_namespace0_generated_35_finish(server, &nsMapping);
retVal |= function_namespace0_generated_34_finish(server, &nsMapping);
retVal |= function_namespace0_generated_33_finish(server, &nsMapping);
retVal |= function_namespace0_generated_32_finish(server, &nsMapping);
retVal |= function_namespace0_generated_31_finish(server, &nsMapping);
retVal |= function_namespace0_generated_30_finish(server, &nsMapping);
retVal |= function_namespace0_generated_29_finish(server, &nsMapping);
retVal |= function_namespace0_generated_28_finish(server, &nsMapping);
retVal |= function_namespace0_generated_27_finish(server, &nsMapping);
retVal |= function_namespace0_generated_26_finish(server, &nsMapping);
retVal |= function_namespace0_generated_25_finish(server, &nsMapping);
retVal |= function_namespace0_generated_24_finish(server, &nsMapping);
retVal |= function_namespace0_generated_23_finish(server, &nsMapping);
retVal |= function_namespace0_generated_22_finish(server, &nsMapping);
retVal |= function_namespace0_generated_21_finish(server, &nsMapping);
retVal |= function_namespace0_generated_20_finish(server, &nsMapping);
retVal |= function_namespace0_generated_19_finish(server, &nsMapping);
retVal |= function_namespace0_generated_18_finish(server, &nsMapping);
retVal |= function_namespace0_generated_17_finish(server, &nsMapping);
retVal |= function_namespace0_generated_16_finish(server, &nsMapping);
retVal |= function_namespace0_generated_15_finish(server, &nsMapping);
retVal |= function_namespace0_generated_14_finish(server, &nsMapping);
retVal |= function_namespace0_generated_13_finish(server, &nsMapping);
retVal |= function_namespace0_generated_12_finish(server, &nsMapping);
retVal |= function_namespace0_generated_11_finish(server, &nsMapping);
return retVal;
}

/**** amalgamated original file "/src/client/ua_client.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015 (c) hfaham
 *    Copyright 2015-2017 (c) Florian Palm
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2015 (c) Holger Jeromin
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lykurg
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Kalycito Infotech Private Limited
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 *    Copyright 2022 (c) Linutronix GmbH (Author: Muddasir Shakil)
 */



static void
clientHouseKeeping(UA_Client *client, void *_);

/********************/
/* Client Lifecycle */
/********************/

UA_StatusCode
UA_ClientConfig_copy(UA_ClientConfig const *src, UA_ClientConfig *dst){
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    retval = UA_ApplicationDescription_copy(&src->clientDescription, &dst->clientDescription);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_ExtensionObject_copy(&src->userIdentityToken, &dst->userIdentityToken);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_String_copy(&src->securityPolicyUri, &dst->securityPolicyUri);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_EndpointDescription_copy(&src->endpoint, &dst->endpoint);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_UserTokenPolicy_copy(&src->userTokenPolicy, &dst->userTokenPolicy);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_Array_copy(src->sessionLocaleIds, src->sessionLocaleIdsSize,
                           (void **)&dst->sessionLocaleIds, &UA_TYPES[UA_TYPES_LOCALEID]);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    dst->sessionLocaleIdsSize = src->sessionLocaleIdsSize;
    dst->connectivityCheckInterval = src->connectivityCheckInterval;
    dst->certificateVerification = src->certificateVerification;
    dst->clientContext = src->clientContext;
    dst->customDataTypes = src->customDataTypes;
    dst->eventLoop = src->eventLoop;
    dst->externalEventLoop = src->externalEventLoop;
    dst->inactivityCallback = src->inactivityCallback;
    dst->localConnectionConfig = src->localConnectionConfig;
    dst->logging = src->logging;
    if(src->certificateVerification.logging == NULL)
        dst->certificateVerification.logging = dst->logging;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    dst->outStandingPublishRequests = src->outStandingPublishRequests;
#endif
    dst->requestedSessionTimeout = src->requestedSessionTimeout;
    dst->secureChannelLifeTime = src->secureChannelLifeTime;
    dst->securityMode = src->securityMode;
    dst->stateCallback = src->stateCallback;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    dst->subscriptionInactivityCallback = src->subscriptionInactivityCallback;
#endif
    dst->timeout = src->timeout;
    dst->userTokenPolicy = src->userTokenPolicy;
    dst->securityPolicies = src->securityPolicies;
    dst->securityPoliciesSize = src->securityPoliciesSize;
    dst->authSecurityPolicies = src->authSecurityPolicies;
    dst->authSecurityPoliciesSize = src->authSecurityPoliciesSize;

cleanup:
    if(retval != UA_STATUSCODE_GOOD) {
        /* _clear will free the plugins in dst that are a shallow copy from src. */
        dst->authSecurityPolicies = NULL;
        dst->certificateVerification.context = NULL;
        dst->eventLoop = NULL;
        dst->logging = NULL;
        dst->securityPolicies = NULL;
        UA_ClientConfig_clear(dst);
    }
    return retval;
}

UA_Client *
UA_Client_newWithConfig(const UA_ClientConfig *config) {
    if(!config)
        return NULL;
    UA_Client *client = (UA_Client*)UA_malloc(sizeof(UA_Client));
    if(!client)
        return NULL;
    memset(client, 0, sizeof(UA_Client));
    client->config = *config;

    UA_SecureChannel_init(&client->channel);
    client->channel.config = client->config.localConnectionConfig;
    client->connectStatus = UA_STATUSCODE_GOOD;

#if UA_MULTITHREADING >= 100
    UA_LOCK_INIT(&client->clientMutex);
#endif

    /* Initialize the namespace mapping */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    size_t initialNs = 2 + config->namespacesSize;
    client->namespaces = (UA_String*)UA_calloc(initialNs, sizeof(UA_String));
    if(!client->namespaces)
        goto error;

    client->namespacesSize = initialNs;
    client->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
    client->namespaces[1] = UA_STRING_NULL; /* Gets set when we connect to the server */
    for(size_t i = 0; i < config->namespacesSize; i++) {
        res |= UA_String_copy(&client->namespaces[i+2], &config->namespaces[i]);
    }
    if(res != UA_STATUSCODE_GOOD)
        goto error;

    return client;

error:
    memset(&client->config, 0, sizeof(UA_ClientConfig));
    UA_Client_delete(client);
    return NULL;
}

void
UA_ClientConfig_clear(UA_ClientConfig *config) {
    UA_ApplicationDescription_clear(&config->clientDescription);
    UA_String_clear(&config->endpointUrl);
    UA_ExtensionObject_clear(&config->userIdentityToken);

    /* Delete the SecurityPolicies for Authentication */
    if(config->authSecurityPolicies != 0) {
        for(size_t i = 0; i < config->authSecurityPoliciesSize; i++)
            config->authSecurityPolicies[i].clear(&config->authSecurityPolicies[i]);
        UA_free(config->authSecurityPolicies);
        config->authSecurityPolicies = 0;
    }
    UA_String_clear(&config->securityPolicyUri);
    UA_String_clear(&config->authSecurityPolicyUri);

    UA_EndpointDescription_clear(&config->endpoint);
    UA_UserTokenPolicy_clear(&config->userTokenPolicy);

    UA_String_clear(&config->applicationUri);

    if(config->certificateVerification.clear)
        config->certificateVerification.clear(&config->certificateVerification);

    /* Delete the SecurityPolicies */
    if(config->securityPolicies != 0) {
        for(size_t i = 0; i < config->securityPoliciesSize; i++)
            config->securityPolicies[i].clear(&config->securityPolicies[i]);
        UA_free(config->securityPolicies);
        config->securityPolicies = 0;
    }

    /* Stop and delete the EventLoop */
    UA_EventLoop *el = config->eventLoop;
    if(el && !config->externalEventLoop) {
        if(el->state != UA_EVENTLOOPSTATE_FRESH &&
           el->state != UA_EVENTLOOPSTATE_STOPPED) {
            el->stop(el);
            while(el->state != UA_EVENTLOOPSTATE_STOPPED) {
                el->run(el, 100);
            }
        }
        el->free(el);
        config->eventLoop = NULL;
    }

    /* Logging */
    if(config->logging != NULL && config->logging->clear != NULL)
        config->logging->clear(config->logging);
    config->logging = NULL;

    UA_String_clear(&config->sessionName);
    if(config->sessionLocaleIdsSize > 0 && config->sessionLocaleIds) {
        UA_Array_delete(config->sessionLocaleIds,
                        config->sessionLocaleIdsSize, &UA_TYPES[UA_TYPES_LOCALEID]);
    }
    config->sessionLocaleIds = NULL;
    config->sessionLocaleIdsSize = 0;

    /* Custom Data Types */
    UA_cleanupDataTypeWithCustom(config->customDataTypes);

#ifdef UA_ENABLE_ENCRYPTION
    config->privateKeyPasswordCallback = NULL;
#endif
}

void
UA_ClientConfig_delete(UA_ClientConfig *config){
    UA_assert(config != NULL);
    UA_ClientConfig_clear(config);
    UA_free(config);
}

static void
UA_Client_clear(UA_Client *client) {
    /* Prevent new async service calls in UA_Client_AsyncService_removeAll */
    UA_SessionState oldState = client->sessionState;
    client->sessionState = UA_SESSIONSTATE_CLOSING;

    /* Delete the async service calls with BADHSUTDOWN */
    __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN);

    /* Reset to the old state to properly close the session */
    client->sessionState = oldState;

    UA_Client_disconnect(client);

    /* Prevent reconnection attempts during the EventLoop teardown
     * in UA_ClientConfig_clear */
    client->connectStatus = UA_STATUSCODE_BADSHUTDOWN;

    UA_String_clear(&client->discoveryUrl);
    UA_EndpointDescription_clear(&client->endpoint);

    UA_ByteString_clear(&client->serverSessionNonce);
    UA_ByteString_clear(&client->clientSessionNonce);

    /* Delete the subscriptions */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    __Client_Subscriptions_clear(client);
#endif

    /* Remove the internal regular callback */
    UA_Client_removeCallback(client, client->houseKeepingCallbackId);
    client->houseKeepingCallbackId = 0;

    /* Clean up the SecureChannel */
    UA_SecureChannel_clear(&client->channel);

    /* Free the namespace mapping */
    UA_Array_delete(client->namespaces, client->namespacesSize,
                    &UA_TYPES[UA_TYPES_STRING]);
    client->namespaces = NULL;
    client->namespacesSize = 0;

    /* Call the application notification callback */
    UA_ClientConfig *config = &client->config;
    if(config->lifecycleNotificationCallback)
        config->lifecycleNotificationCallback(client, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STOPPED,
                                              UA_KEYVALUEMAP_NULL);
    if(config->globalNotificationCallback)
        config->globalNotificationCallback(client, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STOPPED,
                                           UA_KEYVALUEMAP_NULL);

#if UA_MULTITHREADING >= 100
    UA_LOCK_DESTROY(&client->clientMutex);
#endif
}

void
UA_Client_delete(UA_Client* client) {
    UA_Client_disconnect(client);
    UA_Client_clear(client);
    UA_ClientConfig_clear(&client->config);
    UA_free(client);
}

void
UA_Client_getState(UA_Client *client, UA_SecureChannelState *channelState,
                   UA_SessionState *sessionState, UA_StatusCode *connectStatus) {
    lockClient(client);
    if(channelState)
        *channelState = client->channel.state;
    if(sessionState)
        *sessionState = client->sessionState;
    if(connectStatus)
        *connectStatus = client->connectStatus;
    unlockClient(client);
}

UA_ClientConfig *
UA_Client_getConfig(UA_Client *client) {
    if(!client)
        return NULL;
    return &client->config;
}

#if UA_LOGLEVEL <= 300
static const char *channelStateTexts[14] = {
    "Closed", "ReverseListening", "Connecting", "Connected", "ReverseConnected", "RHESent", "HELSent", "HELReceived", "ACKSent",
    "AckReceived", "OPNSent", "Open", "Closing"};
static const char *sessionStateTexts[6] =
    {"Closed", "CreateRequested", "Created",
     "ActivateRequested", "Activated", "Closing"};
#endif

void
setConnectStatus(UA_Client *client, UA_StatusCode status) {
    UA_LOCK_ASSERT(&client->clientMutex);

    client->connectStatus = status;
    if(status != UA_STATUSCODE_GOOD)
        closeSecureChannel(client);

    notifyClientState(client);
}

void
notifyClientState(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    if(client->connectStatus == client->oldConnectStatus &&
       client->channel.state == client->oldChannelState &&
       client->sessionState == client->oldSessionState)
        return;

#if UA_LOGLEVEL <= 300
    UA_Boolean info = (client->connectStatus != UA_STATUSCODE_GOOD);
    if(client->oldChannelState != client->channel.state)
        info |= (client->channel.state == UA_SECURECHANNELSTATE_OPEN ||
                 client->channel.state == UA_SECURECHANNELSTATE_CLOSED);
    if(client->oldSessionState != client->sessionState)
        info |= (client->sessionState == UA_SESSIONSTATE_CREATED ||
                 client->sessionState == UA_SESSIONSTATE_ACTIVATED ||
                 client->sessionState == UA_SESSIONSTATE_CLOSED);

    const char *channelStateText = channelStateTexts[client->channel.state];
    const char *sessionStateText = sessionStateTexts[client->sessionState];
    const char *connectStatusText = UA_StatusCode_name(client->connectStatus);

    if(info)
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Client Status: ChannelState: %s, SessionState: %s, ConnectStatus: %s",
                    channelStateText, sessionStateText, connectStatusText);
    else
        UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Client Status: ChannelState: %s, SessionState: %s, ConnectStatus: %s",
                     channelStateText, sessionStateText, connectStatusText);
#endif

    client->oldConnectStatus = client->connectStatus;
    client->oldChannelState = client->channel.state;
    client->oldSessionState = client->sessionState;

    if(client->config.stateCallback)
        client->config.stateCallback(client, client->channel.state,
                                     client->sessionState, client->connectStatus);
}

/****************/
/* Raw Services */
/****************/

/* For both synchronous and asynchronous service calls */
static UA_StatusCode
sendRequest(UA_Client *client, const void *request,
            const UA_DataType *requestType, UA_UInt32 *requestId) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Renew SecureChannel if necessary */
    __Client_renewSecureChannel(client);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return client->connectStatus;

    UA_EventLoop *el = client->config.eventLoop;

    /* Adjusting the request header. The const attribute is violated, but we
     * reset to the original state before returning. Use the AuthenticationToken
     * only once the session is active (or to activate / close it). */
    UA_RequestHeader *rr = (UA_RequestHeader*)(uintptr_t)request;
    UA_NodeId oldToken = rr->authenticationToken; /* Put back in place later */

    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED ||
       requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST] ||
       requestType == &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST])
        rr->authenticationToken = client->authenticationToken;
    rr->timestamp = el->dateTime_now(el);

    /* Create a unique handle >100,000 if not manually defined. The handle is
     * not necessarily unique when manually defined and used to cancel async
     * service requests. */
    if(rr->requestHandle == 0) {
        if(UA_UNLIKELY(client->requestHandle < 100000))
            client->requestHandle = 100000;
        rr->requestHandle = ++client->requestHandle;
    }

    /* Set the timeout hint if not manually defined */
    if(rr->timeoutHint == 0)
        rr->timeoutHint = client->config.timeout;

    /* Generate the request id */
    UA_UInt32 rqId = ++client->requestId;

#ifdef UA_ENABLE_TYPEDESCRIPTION
    UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                         "Sending request with RequestId %u of type %s",
                         (unsigned)rqId, requestType->typeName);
#else
    UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                         "Sending request with RequestId %u of type %" PRIu32,
                         (unsigned)rqId, requestType->binaryEncodingId.identifier.numeric);
#endif

    /* Send the message */
    UA_StatusCode retval =
        UA_SecureChannel_sendMSG(&client->channel, rqId, rr, requestType);

    rr->authenticationToken = oldToken; /* Set back to the original token */

    /* Sending failed. The SecureChannel cannot recover from that. Call
     * closeSecureChannel to a) close from our end and b) set the session to
     * non-activated. */
    if(retval != UA_STATUSCODE_GOOD)
        closeSecureChannel(client);

    /* Return the request id */
    *requestId = rqId;
    return retval;
}

static const UA_NodeId
serviceFaultId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_SERVICEFAULT_ENCODING_DEFAULTBINARY}};

/* Look for the async callback in the linked list, execute and delete it */
static UA_StatusCode
processMSGResponse(UA_Client *client, UA_UInt32 requestId,
                   const UA_ByteString *msg) {
    UA_ClientConfig *config = &client->config;

    /* Find the callback */
    AsyncServiceCall *ac;
    LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) {
        if(ac->requestId == requestId)
            break;
    }

    /* Part 6, 6.7.6: After the security validation is complete the receiver
     * shall verify the RequestId and the SequenceNumber. If these checks fail a
     * Bad_SecurityChecksFailed error is reported. The RequestId only needs to
     * be verified by the Client since only the Client knows if it is valid or
     * not.
     *
     * But! If an async request has timed out, the RequestId is no longer found.
     * In theory the server should send an error back before the timeout. But
     * not all do. In these cases we don't want to close the entire
     * SecureChannel and just log a warning. The service callback has already
     * been notified about the timeout before. */
    if(!ac) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_CLIENT,
                       "Request with unknown RequestId %u", requestId);
        return UA_STATUSCODE_GOOD;
    }

    UA_Response asyncResponse;
    UA_Response *response = (ac->syncResponse) ? ac->syncResponse : &asyncResponse;
    const UA_DataType *responseType = ac->responseType;

    /* Dequeue ac. We might disconnect the client (remove all ac) in the callback. */
    LIST_REMOVE(ac, pointers);

    /* Decode the response type */
    size_t offset = 0;
    UA_NodeId responseTypeId;
    UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &responseTypeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto process;

    /* Verify the type of the response */
    if(!UA_NodeId_equal(&responseTypeId, &ac->responseType->binaryEncodingId)) {
        /* Initialize before switching the responseType to ServiceFault.
         * Otherwise the decoding will leave fields from the original response
         * type uninitialized. */
        UA_init(response, ac->responseType);
        if(UA_NodeId_equal(&responseTypeId, &serviceFaultId)) {
            /* Decode as a ServiceFault, i.e. only the response header */
            UA_LOG_DEBUG(config->logging, UA_LOGCATEGORY_CLIENT,
                         "Received a ServiceFault response");
            responseType = &UA_TYPES[UA_TYPES_SERVICEFAULT];
        } else {
            UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_CLIENT,
                         "Service response type does not match");
            retval = UA_STATUSCODE_BADCOMMUNICATIONERROR;
            goto process; /* Do not decode */
        }
    }

    /* Decode the response */
#ifdef UA_ENABLE_TYPEDESCRIPTION
    UA_LOG_DEBUG(config->logging, UA_LOGCATEGORY_CLIENT,
                 "Decode a message of type %s", responseType->typeName);
#else
    UA_LOG_DEBUG(config->logging, UA_LOGCATEGORY_CLIENT,
                 "Decode a message of type %" PRIu32,
                 responseTypeId.identifier.numeric);
#endif

    UA_DecodeBinaryOptions opt;
    memset(&opt, 0, sizeof(UA_DecodeBinaryOptions));
    opt.customTypes = config->customDataTypes;
    opt.namespaceMapping = client->channel.namespaceMapping;
    retval = UA_decodeBinaryInternal(msg, &offset, response, responseType, &opt);

 process:
    /* Process the received MSG response */
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_CLIENT,
                       "Could not decode the response with RequestId %u with status %s",
                       (unsigned)requestId, UA_StatusCode_name(retval));
        response->responseHeader.serviceResult = retval;
    }

    /* The Session closed. The current response is processed with the return code.
     * The next request first recreates a session. */
    if(responseType != &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE] &&
       (response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONIDINVALID ||
        response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED)) {
        /* Clean up the session information and reset the state */
        cleanupSession(client);

        if(config->noNewSession) {
            /* Configuration option to not create a new Session. Disconnect the
             * client. */
            client->connectStatus = response->responseHeader.serviceResult;
            UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_CLIENT,
                         "Session cannot be activated with StatusCode %s. "
                         "The client is configured not to create a new Session.",
                         UA_StatusCode_name(client->connectStatus));
            closeSecureChannel(client);
        } else {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_CLIENT,
                           "Session no longer valid. A new Session is created for the next "
                           "Service request but we do not re-send the current request.");
        }
    }

    /* Prepare the notification payload */
    UA_ApplicationNotificationType nt;
    static UA_THREAD_LOCAL UA_KeyValuePair notifyPayload[4] = {
        {{0, UA_STRING_STATIC("securechannel-id")}, {0}},
        {{0, UA_STRING_STATIC("session-id")}, {0}},
        {{0, UA_STRING_STATIC("request-id")}, {0}},
        {{0, UA_STRING_STATIC("service-type")}, {0}}
    };
    UA_KeyValueMap notifyPayloadMap = {4, notifyPayload};
    if(config->globalNotificationCallback || config->serviceNotificationCallback) {
        UA_Variant_setScalar(&notifyPayload[0].value,
                             &client->channel.securityToken.channelId,
                             &UA_TYPES[UA_TYPES_UINT32]);
        UA_Variant_setScalar(&notifyPayload[1].value, &client->sessionId,
                             &UA_TYPES[UA_TYPES_NODEID]);
        UA_Variant_setScalar(&notifyPayload[2].value, &requestId,
                             &UA_TYPES[UA_TYPES_UINT32]);
        UA_Variant_setScalar(&notifyPayload[3].value,
                             (void *)(uintptr_t)&ac->responseType->typeId,
                             &UA_TYPES[UA_TYPES_NODEID]);
    }

    if(ac->callback) {
        /* Notify with UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_BEGIN before the
         * service response is processed asynchronously */
        nt = UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_BEGIN;
        if(config->serviceNotificationCallback)
            config->serviceNotificationCallback(client, nt, notifyPayloadMap);
        if(config->globalNotificationCallback)
            config->globalNotificationCallback(client, nt, notifyPayloadMap);

        /* Call the async callback */
        ac->callback(client, ac->userdata, requestId, response);
    }

    /* Always notify with UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_END that the
     * service was processed. For the synchronous case this gets called before
     * the response is returned together with the main control flow. */
    nt = UA_APPLICATIONNOTIFICATIONTYPE_SERVICE_END;
    if(config->serviceNotificationCallback)
        config->serviceNotificationCallback(client, nt, notifyPayloadMap);
    if(config->globalNotificationCallback)
        config->globalNotificationCallback(client, nt, notifyPayloadMap);

    /* Clean up */
    UA_NodeId_clear(&responseTypeId);
    if(!ac->syncResponse) {
        UA_clear(response, ac->responseType);
        UA_free(ac);
    } else {
        /* Return a special status code after processing a synchronous message.
         * This makes the client return control immediately. */
        ac->syncResponse = NULL; /* Indicate that response was received */
        if(retval == UA_STATUSCODE_GOOD)
            retval = UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY;
    }
    return retval;
}

UA_StatusCode
processServiceResponse(UA_Client *client, UA_SecureChannel *channel,
                       UA_MessageType messageType, UA_UInt32 requestId,
                       UA_ByteString *message) {
    if(!UA_SecureChannel_isConnected(channel)) {
        if(messageType == UA_MESSAGETYPE_MSG) {
            UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Discard MSG message "
                                 "with RequestId %u as the SecureChannel is not connected",
                                 requestId);
        } else {
            UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Discard message "
                                 "as the SecureChannel is not connected");
        }
        return UA_STATUSCODE_BADCONNECTIONCLOSED;
    }

    switch(messageType) {
    case UA_MESSAGETYPE_RHE:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process RHE message");
        processRHEMessage(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_ACK:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process ACK message");
        processACKResponse(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_OPN:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process OPN message");
        processOPNResponse(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_ERR:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process ERR message");
        processERRResponse(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_MSG:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process MSG message "
                             "with RequestId %u", requestId);
        return processMSGResponse(client, requestId, message);
    default:
        UA_LOG_TRACE_CHANNEL(client->config.logging, channel,
                             "Invalid message type");
        channel->state = UA_SECURECHANNELSTATE_CLOSING;
        return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
    }
}

void
__Client_Service(UA_Client *client, const void *request,
                 const UA_DataType *requestType, void *response,
                 const UA_DataType *responseType) {
    UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response;

    /* Initialize. Response is valied in case of aborting. */
    UA_init(response, responseType);

    /* Verify that the EventLoop is running */
    UA_EventLoop *el = client->config.eventLoop;
    if(!el || el->state != UA_EVENTLOOPSTATE_STARTED) {
        respHeader->serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* Check that the SecureChannel is open and also a Session active (if we
     * want a Session). Otherwise reopen. */
    if(!isFullyConnected(client)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Re-establish the connection for the synchronous service call");
        connectSync(client);
        if(client->connectStatus != UA_STATUSCODE_GOOD) {
            respHeader->serviceResult = client->connectStatus;
            return;
        }
    }

    /* Store the channelId to detect if the channel was changed by a
     * reconnection within the EventLoop run method. */
    UA_UInt32 channelId = client->channel.securityToken.channelId;

    /* Send the request */
    UA_UInt32 requestId = 0;
    UA_StatusCode retval = sendRequest(client, request, requestType, &requestId);
    if(retval != UA_STATUSCODE_GOOD) {
        /* If sending failed, the status is set to closing. The SecureChannel is
         * the actually closed in the next iteration of the EventLoop. */
        UA_assert(client->channel.state == UA_SECURECHANNELSTATE_CLOSING ||
                  client->channel.state == UA_SECURECHANNELSTATE_CLOSED);
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Sending the request failed with status %s",
                       UA_StatusCode_name(retval));
        notifyClientState(client);
        respHeader->serviceResult = retval;
        return;
    }

    /* Temporarily insert an AsyncServiceCall */
    const UA_RequestHeader *rh = (const UA_RequestHeader*)request;
    AsyncServiceCall ac;
    ac.callback = NULL;
    ac.userdata = NULL;
    ac.responseType = responseType;
    ac.syncResponse = (UA_Response*)response;
    ac.requestId = requestId;
    ac.start = el->dateTime_nowMonotonic(el); /* Start timeout after sending */
    ac.timeout = rh->timeoutHint;
    ac.requestHandle = rh->requestHandle;
    if(ac.timeout == 0)
        ac.timeout = UA_UINT32_MAX; /* 0 -> unlimited */

    LIST_INSERT_HEAD(&client->asyncServiceCalls, &ac, pointers);

    /* Time until which the request has to be answered */
    UA_DateTime maxDate = ac.start + ((UA_DateTime)ac.timeout * UA_DATETIME_MSEC);

    /* Run the EventLoop until the request was processed, the request has timed
     * out or the client connection fails */
    UA_UInt32 timeout_remaining = ac.timeout;
    while(true) {
        /* Unlock before dropping into the EventLoop. The client lock is
         * re-taken in the network callback if an event occurs. */
        retval = el->run(el, timeout_remaining);

        /* Was the response received? In that case we can directly return. The
         * ac was already removed from the internal linked list. */
        if(ac.syncResponse == NULL)
            return;

        /* Check the status. Do not try to resend if the connection breaks.
         * Leave this to the application-level user. For example, we do not want
         * to call a method twice is the connection broke after sending the
         * request. */
        if(retval != UA_STATUSCODE_GOOD)
            break;

        /* The connection was lost */
        retval = client->connectStatus;
        if(retval != UA_STATUSCODE_GOOD)
            break;

        /* The channel is no longer the same or was closed */
        if(channelId != client->channel.securityToken.channelId) {
            retval = UA_STATUSCODE_BADSECURECHANNELCLOSED;
            break;
        }

        /* Update the remaining timeout or break */
        UA_DateTime now = ac.start = el->dateTime_nowMonotonic(el);
        if(now > maxDate) {
            retval = UA_STATUSCODE_BADTIMEOUT;
            break;
        }
        timeout_remaining = (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC);
    }

    /* Detach from the internal async service list */
    LIST_REMOVE(&ac, pointers);

    /* Return the status code */
    respHeader->serviceResult = retval;
}

/***********************************/
/* Handling of Async Service Calls */
/***********************************/

static void
__Client_AsyncService_cancel(UA_Client *client, AsyncServiceCall *ac,
                             UA_StatusCode statusCode) {
    /* Set the status for the synchronous service call. Don't free the ac. */
    if(ac->syncResponse) {
        ac->syncResponse->responseHeader.serviceResult = statusCode;
        ac->syncResponse = NULL; /* Indicate the async service call was processed */
        return;
    }

    if(ac->callback) {
        /* Create an empty response with the statuscode and call the callback */
        UA_Response response;
        UA_init(&response, ac->responseType);
        response.responseHeader.serviceResult = statusCode;
        ac->callback(client, ac->userdata, ac->requestId, &response);

        /* Clean up the response. The user callback might move data into it. For
         * whatever reasons. */
        UA_clear(&response, ac->responseType);
    }

    UA_free(ac);
}

void
__Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode) {
    /* Make this function reentrant. One of the async callbacks could indirectly
     * operate on the list. Moving all elements to a local list before iterating
     * that. */
    UA_AsyncServiceList asyncServiceCalls = client->asyncServiceCalls;
    LIST_INIT(&client->asyncServiceCalls);
    if(asyncServiceCalls.lh_first)
        asyncServiceCalls.lh_first->pointers.le_prev = &asyncServiceCalls.lh_first;

    /* Cancel and remove the elements from the local list */
    AsyncServiceCall *ac, *ac_tmp;
    LIST_FOREACH_SAFE(ac, &asyncServiceCalls, pointers, ac_tmp) {
        LIST_REMOVE(ac, pointers);
        __Client_AsyncService_cancel(client, ac, statusCode);
    }
}

UA_StatusCode
__Client_AsyncService(UA_Client *client, const void *request,
                      const UA_DataType *requestType,
                      UA_ClientAsyncServiceCallback callback,
                      const UA_DataType *responseType,
                      void *userdata, UA_UInt32 *requestId) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Is the SecureChannel connected? */
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "SecureChannel must be connected to send request");
        return UA_STATUSCODE_BADSERVERNOTCONNECTED;
    }

    /* Prepare the entry for the linked list */
    AsyncServiceCall *ac = (AsyncServiceCall*)UA_malloc(sizeof(AsyncServiceCall));
    if(!ac)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Call the service and set the requestId */
    UA_StatusCode retval = sendRequest(client, request, requestType, &ac->requestId);
    if(retval != UA_STATUSCODE_GOOD) {
        /* If sending failed, the status is set to closing. The SecureChannel is
         * the actually closed in the next iteration of the EventLoop. */
        UA_assert(client->channel.state == UA_SECURECHANNELSTATE_CLOSING ||
                  client->channel.state == UA_SECURECHANNELSTATE_CLOSED);
        UA_free(ac);
        notifyClientState(client);
        return retval;
    }

    /* Set up the AsyncServiceCall for processing the response */
    UA_EventLoop *el = client->config.eventLoop;
    const UA_RequestHeader *rh = (const UA_RequestHeader*)request;
    ac->callback = callback;
    ac->responseType = responseType;
    ac->userdata = userdata;
    ac->syncResponse = NULL;
    ac->start = el->dateTime_nowMonotonic(el);
    ac->timeout = rh->timeoutHint;
    ac->requestHandle = rh->requestHandle;
    if(ac->timeout == 0)
        ac->timeout = UA_UINT32_MAX; /* 0 -> unlimited */

    LIST_INSERT_HEAD(&client->asyncServiceCalls, ac, pointers);

    /* Return the generated request id */
    if(requestId)
        *requestId = ac->requestId;

    /* Notify the userland if a change happened */
    notifyClientState(client);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle, UA_UInt32 *cancelCount) {
    UA_CancelRequest creq;
    UA_CancelRequest_init(&creq);
    creq.requestHandle = requestHandle;
    UA_CancelResponse cresp;
    UA_CancelResponse_init(&cresp);
    __Client_Service(client, &creq, &UA_TYPES[UA_TYPES_CANCELREQUEST],
                     &cresp, &UA_TYPES[UA_TYPES_CANCELRESPONSE]);
    if(cancelCount)
        *cancelCount = cresp.cancelCount;
    UA_StatusCode res = cresp.responseHeader.serviceResult;
    UA_CancelResponse_clear(&cresp);
    return res;
}

UA_StatusCode
UA_Client_cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle,
                                UA_UInt32 *cancelCount) {
    lockClient(client);
    UA_StatusCode res = cancelByRequestHandle(client, requestHandle, cancelCount);
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_cancelByRequestId(UA_Client *client, UA_UInt32 requestId,
                            UA_UInt32 *cancelCount) {
    lockClient(client);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    AsyncServiceCall *ac;
    LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) {
        if(ac->requestId != requestId)
            continue;
        res = cancelByRequestHandle(client, ac->requestHandle, cancelCount);
        break;
    }
    unlockClient(client);
    return res;
}

/*******************/
/* Timed Callbacks */
/*******************/

UA_StatusCode
UA_Client_addTimedCallback(UA_Client *client, UA_ClientCallback callback,
                           void *data, UA_DateTime date, UA_UInt64 *callbackId) {
    if(!client->config.eventLoop)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockClient(client);
    UA_StatusCode res = client->config.eventLoop->
        addTimer(client->config.eventLoop, (UA_Callback)callback,
                 client, data, 0.0, &date, UA_TIMERPOLICY_ONCE, callbackId);
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback,
                              void *data, UA_Double interval_ms, UA_UInt64 *callbackId) {
    if(!client->config.eventLoop)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockClient(client);
    UA_StatusCode res = client->config.eventLoop->
        addTimer(client->config.eventLoop, (UA_Callback)callback, client, data,
                 interval_ms, NULL, UA_TIMERPOLICY_CURRENTTIME, callbackId);
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_changeRepeatedCallbackInterval(UA_Client *client, UA_UInt64 callbackId,
                                         UA_Double interval_ms) {
    if(!client->config.eventLoop)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockClient(client);
    UA_StatusCode res = client->config.eventLoop->
        modifyTimer(client->config.eventLoop, callbackId, interval_ms,
                    NULL, UA_TIMERPOLICY_CURRENTTIME);
    unlockClient(client);
    return res;
}

void
UA_Client_removeCallback(UA_Client *client, UA_UInt64 callbackId) {
    if(!client->config.eventLoop)
        return;
    lockClient(client);
    client->config.eventLoop->removeTimer(client->config.eventLoop, callbackId);
    unlockClient(client);
}

/**********************/
/* Housekeeping Tasks */
/**********************/

static void
asyncServiceTimeoutCheck(UA_Client *client) {
    /* Make this function reentrant. One of the async callbacks could indirectly
     * operate on the list. Moving all elements to a local list before iterating
     * that. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_AsyncServiceList asyncServiceCalls;
    AsyncServiceCall *ac, *ac_tmp;
    LIST_INIT(&asyncServiceCalls);
    LIST_FOREACH_SAFE(ac, &client->asyncServiceCalls, pointers, ac_tmp) {
        if(!ac->timeout)
           continue;
        if(ac->start + (UA_DateTime)(ac->timeout * UA_DATETIME_MSEC) <= now) {
            LIST_REMOVE(ac, pointers);
            LIST_INSERT_HEAD(&asyncServiceCalls, ac, pointers);
        }
    }

    /* Cancel and remove the elements from the local list */
    LIST_FOREACH_SAFE(ac, &asyncServiceCalls, pointers, ac_tmp) {
        LIST_REMOVE(ac, pointers);
        /* Reset the pointers to pacify clang-analyzer */
        ac->pointers.le_next = NULL;
        ac->pointers.le_prev = NULL;
        __Client_AsyncService_cancel(client, ac, UA_STATUSCODE_BADTIMEOUT);
    }
}

static void
backgroundConnectivityCallback(UA_Client *client, void *userdata,
                               UA_UInt32 requestId, const UA_ReadResponse *response) {
    lockClient(client);
    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTIMEOUT) {
        if(client->config.inactivityCallback)
            client->config.inactivityCallback(client);
    }
    UA_EventLoop *el = client->config.eventLoop;
    client->pendingConnectivityCheck = false;
    client->lastConnectivityCheck = el->dateTime_nowMonotonic(el);
    unlockClient(client);
}

static void
__Client_backgroundConnectivity(UA_Client *client) {
    if(!client->config.connectivityCheckInterval)
        return;

    if(client->pendingConnectivityCheck)
        return;

    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime nextDate = client->lastConnectivityCheck +
        (UA_DateTime)(client->config.connectivityCheckInterval * UA_DATETIME_MSEC);
    if(now <= nextDate)
        return;

    /* Prepare the request */
    UA_ReadValueId rvid;
    UA_ReadValueId_init(&rvid);
    rvid.attributeId = UA_ATTRIBUTEID_VALUE;
    rvid.nodeId = UA_NS0ID(SERVER_SERVERSTATUS_STATE);
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = &rvid;
    request.nodesToReadSize = 1;
    UA_StatusCode retval =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
                              (UA_ClientAsyncServiceCallback)backgroundConnectivityCallback,
                              &UA_TYPES[UA_TYPES_READRESPONSE], NULL, NULL);
    if(retval == UA_STATUSCODE_GOOD)
        client->pendingConnectivityCheck = true;
}

/* Regular housekeeping activities in the client -- called via a cyclic callback */
static void
clientHouseKeeping(UA_Client *client, void *_) {
    lockClient(client);

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Internally check the the client state and "
                 "required activities");

    /* Renew Secure Channel */
    __Client_renewSecureChannel(client);

    /* Send read requests from time to time to test the connectivity */
    __Client_backgroundConnectivity(client);

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Feed the server PublishRequests for the Subscriptions */
    __Client_Subscriptions_backgroundPublish(client);

    /* Check for inactive Subscriptions */
    __Client_Subscriptions_backgroundPublishInactivityCheck(client);
#endif

    /* Did async services time out? Process callbacks with an error code */
    asyncServiceTimeoutCheck(client);

    /* Log and notify user if the client state has changed */
    notifyClientState(client);

    unlockClient(client);
}

UA_StatusCode
__UA_Client_startup(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_ClientConfig *config = &client->config;
    UA_EventLoop *el = config->eventLoop;
    UA_CHECK_ERROR(el != NULL,
                   return UA_STATUSCODE_BADINTERNALERROR,
                   config->logging, UA_LOGCATEGORY_CLIENT,
                   "No EventLoop configured");

    /* Set up the repeated timer callback for checking the internal state. Like
     * in the public API UA_Client_addRepeatedCallback, but without locking the
     * mutex again */
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    if(!client->houseKeepingCallbackId) {
        rv = el->addTimer(el, (UA_Callback)clientHouseKeeping,
                          client, NULL, 1000.0, NULL,
                          UA_TIMERPOLICY_CURRENTTIME,
                          &client->houseKeepingCallbackId);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Start the EventLoop? */
    if(el->state == UA_EVENTLOOPSTATE_FRESH) {
        rv = el->start(el);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Call the application notification callback */
    if(config->lifecycleNotificationCallback)
        config->lifecycleNotificationCallback(client, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STARTED,
                                              UA_KEYVALUEMAP_NULL);
    if(config->globalNotificationCallback)
        config->globalNotificationCallback(client, UA_APPLICATIONNOTIFICATIONTYPE_LIFECYCLE_STARTED,
                                           UA_KEYVALUEMAP_NULL);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) {
    /* Make sure the EventLoop has been started */
    lockClient(client);
    UA_StatusCode rv = __UA_Client_startup(client);
    unlockClient(client);
    UA_CHECK_STATUS(rv, return rv);

    /* All timers and network events are triggered in the EventLoop. Release the
     * client lock before. The callbacks from the EventLoop take the lock
     * again. */
    UA_EventLoop *el = client->config.eventLoop;
    rv = el->run(el, timeout);
    UA_CHECK_STATUS(rv, return rv);
    return client->connectStatus;
}

const UA_DataType *
UA_Client_findDataType(UA_Client *client, const UA_NodeId *typeId) {
    return UA_findDataTypeWithCustom(typeId, client->config.customDataTypes);
}

/*************************/
/* Connection Attributes */
/*************************/

#define UA_CONNECTIONATTRIBUTESSIZE 3
static const UA_QualifiedName connectionAttributes[UA_CONNECTIONATTRIBUTESSIZE] = {
    {0, UA_STRING_STATIC("serverDescription")},
    {0, UA_STRING_STATIC("securityPolicyUri")},
    {0, UA_STRING_STATIC("securityMode")}
};

static UA_StatusCode
getConnectionttribute(UA_Client *client, const UA_QualifiedName key,
                      UA_Variant *outValue, UA_Boolean copy) {
    if(!outValue)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_Variant localAttr;

    if(UA_QualifiedName_equal(&key, &connectionAttributes[0])) {
        /* ServerDescription */
        UA_Variant_setScalar(&localAttr, &client->endpoint.server,
                             &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
    } else if(UA_QualifiedName_equal(&key, &connectionAttributes[1])) {
        /* SecurityPolicyUri */
        const UA_SecurityPolicy *sp = client->channel.securityPolicy;
        if(!sp)
            return UA_STATUSCODE_BADNOTCONNECTED;
        UA_Variant_setScalar(&localAttr, (void*)(uintptr_t)&sp->policyUri,
                             &UA_TYPES[UA_TYPES_STRING]);
    } else if(UA_QualifiedName_equal(&key, &connectionAttributes[2])) {
        /* SecurityMode */
        UA_Variant_setScalar(&localAttr, &client->channel.securityMode,
                             &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE]);
    } else {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(copy)
        return UA_Variant_copy(&localAttr, outValue);

    localAttr.storageType = UA_VARIANT_DATA_NODELETE;
    *outValue = localAttr;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_getConnectionAttribute(UA_Client *client, const UA_QualifiedName key,
                                 UA_Variant *outValue) {
    lockClient(client);
    UA_StatusCode res = getConnectionttribute(client, key, outValue, false);
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_getConnectionAttributeCopy(UA_Client *client, const UA_QualifiedName key,
                                     UA_Variant *outValue) {
    lockClient(client);
    UA_StatusCode res = getConnectionttribute(client, key, outValue, true);
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_getConnectionAttribute_scalar(UA_Client *client,
                                        const UA_QualifiedName key,
                                        const UA_DataType *type,
                                        void *outValue) {
    lockClient(client);

    UA_Variant attr;
    UA_StatusCode res = getConnectionttribute(client, key, &attr, false);
    if(res != UA_STATUSCODE_GOOD) {
        unlockClient(client);
        return res;
    }

    if(!UA_Variant_hasScalarType(&attr, type)) {
        unlockClient(client);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    memcpy(outValue, attr.data, type->memSize);

    unlockClient(client);
    return UA_STATUSCODE_GOOD;
}

/* Namespace Mapping */

UA_StatusCode
UA_Client_getNamespaceUri(UA_Client *client, UA_UInt16 index,
                          UA_String *nsUri) {
    lockClient(client);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(index < client->namespacesSize)
        res = UA_String_copy(&client->namespaces[index], nsUri);
    else
        res = UA_STATUSCODE_BADNOTFOUND;
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_getNamespaceIndex(UA_Client *client, const UA_String nsUri,
                            UA_UInt16 *outIndex) {
    lockClient(client);
    for(size_t i = 0; i < client->namespacesSize; i++) {
        if(UA_String_equal(&nsUri, &client->namespaces[i])) {
            *outIndex = (UA_UInt16)i;
            unlockClient(client);
            return UA_STATUSCODE_GOOD;
        }
    }
    unlockClient(client);
    return UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
UA_Client_addNamespace(UA_Client *client, const UA_String nsUri,
                       UA_UInt16 *outIndex) {
    UA_StatusCode res = UA_Client_getNamespaceIndex(client, nsUri, outIndex);
    if(res == UA_STATUSCODE_GOOD)
        return res;
    lockClient(client);
    res = UA_Array_appendCopy((void**)&client->namespaces, &client->namespacesSize,
                              &nsUri, &UA_TYPES[UA_TYPES_STRING]);
    if(res == UA_STATUSCODE_GOOD)
        *outIndex = (UA_UInt16)(client->namespacesSize - 1);
    unlockClient(client);
    return res;
}

void lockClient(UA_Client *client) {
    if(UA_LIKELY(client->config.eventLoop && client->config.eventLoop->lock))
        client->config.eventLoop->lock(client->config.eventLoop);
    UA_LOCK(&client->clientMutex);
}

void unlockClient(UA_Client *client) {
    if(UA_LIKELY(client->config.eventLoop && client->config.eventLoop->unlock))
        client->config.eventLoop->unlock(client->config.eventLoop);
    UA_UNLOCK(&client->clientMutex);
}

/**********************/
/* Connect Shorthands */
/**********************/

UA_StatusCode
UA_ClientConfig_setAuthenticationUsername(UA_ClientConfig *config,
                                          const char *username,
                                          const char *password) {
    UA_UserNameIdentityToken* identityToken = UA_UserNameIdentityToken_new();
    if(!identityToken)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    identityToken->userName = UA_STRING_ALLOC(username);
    identityToken->password = UA_BYTESTRING_ALLOC(password);
    UA_ExtensionObject_clear(&config->userIdentityToken);
    UA_ExtensionObject_setValue(&config->userIdentityToken, identityToken,
                                &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_connect(UA_Client *client, const char *endpointUrl) {
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    cc->noSession = false;
    return __UA_Client_connect(client, false, endpointUrl);
}

UA_StatusCode
UA_Client_connectSecureChannel(UA_Client *client, const char *endpointUrl) {
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    cc->noSession = true; /* Don't open a Session */
    return __UA_Client_connect(client, false, endpointUrl);
}

UA_StatusCode
UA_Client_connectAsync(UA_Client *client, const char *endpointUrl) {
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    cc->noSession = false; /* Open a Session */
    return __UA_Client_connect(client, true, endpointUrl);
}

UA_StatusCode
UA_Client_connectSecureChannelAsync(UA_Client *client, const char *endpointUrl) {
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    cc->noSession = true; /* Don't open a Session */
    return __UA_Client_connect(client, true, endpointUrl);
}

UA_StatusCode
UA_Client_connectUsername(UA_Client *client, const char *endpointUrl,
                          const char *username, const char *password) {
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    UA_StatusCode res = UA_ClientConfig_setAuthenticationUsername(cc, username, password);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    return UA_Client_connect(client, endpointUrl);
}

/**********************/
/* Service Shorthands */
/**********************/

void
__UA_Client_Service(UA_Client *client, const void *request,
                    const UA_DataType *requestType, void *response,
                    const UA_DataType *responseType) {
    lockClient(client);
    __Client_Service(client, request, requestType, response, responseType);
    unlockClient(client);
}

UA_ReadResponse
UA_Client_Service_read(UA_Client *client, const UA_ReadRequest request) {
    UA_ReadResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
                        &response, &UA_TYPES[UA_TYPES_READRESPONSE]);
    return response;
}

UA_WriteResponse
UA_Client_Service_write(UA_Client *client, const UA_WriteRequest request) {
    UA_WriteResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_WRITEREQUEST],
                        &response, &UA_TYPES[UA_TYPES_WRITERESPONSE]);
    return response;
}

#ifdef UA_ENABLE_HISTORIZING

UA_HistoryReadResponse
UA_Client_Service_historyRead(UA_Client *client,
                              const UA_HistoryReadRequest request) {
    UA_HistoryReadResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_HISTORYREADREQUEST],
                        &response, &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]);
    return response;
}

UA_HistoryUpdateResponse
UA_Client_Service_historyUpdate(UA_Client *client,
                                const UA_HistoryUpdateRequest request) {
    UA_HistoryUpdateResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST],
                        &response, &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]);
    return response;
}

#endif

UA_CallResponse
UA_Client_Service_call(UA_Client *client,
                       const UA_CallRequest request) {
    UA_CallResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CALLREQUEST],
                        &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]);
    return response;
}

UA_AddNodesResponse
UA_Client_Service_addNodes(UA_Client *client,
                           const UA_AddNodesRequest request) {
    UA_AddNodesResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST],
                        &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]);
    return response;
}

UA_AddReferencesResponse
UA_Client_Service_addReferences(UA_Client *client,
                                const UA_AddReferencesRequest request) {
    UA_AddReferencesResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST],
                        &response, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]);
    return response;
}

UA_DeleteNodesResponse
UA_Client_Service_deleteNodes(UA_Client *client,
                              const UA_DeleteNodesRequest request) {
    UA_DeleteNodesResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST],
                        &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]);
    return response;
}

UA_DeleteReferencesResponse
UA_Client_Service_deleteReferences(UA_Client *client,
                                   const UA_DeleteReferencesRequest request) {
    UA_DeleteReferencesResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST],
                        &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]);
    return response;
}

UA_BrowseResponse
UA_Client_Service_browse(UA_Client *client,
                         const UA_BrowseRequest request) {
    UA_BrowseResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_BROWSEREQUEST],
                        &response, &UA_TYPES[UA_TYPES_BROWSERESPONSE]);
    return response;
}

UA_BrowseNextResponse
UA_Client_Service_browseNext(UA_Client *client,
                             const UA_BrowseNextRequest request) {
    UA_BrowseNextResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST],
                        &response, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]);
    return response;
}

UA_TranslateBrowsePathsToNodeIdsResponse
UA_Client_Service_translateBrowsePathsToNodeIds(UA_Client *client,
    const UA_TranslateBrowsePathsToNodeIdsRequest request) {
    UA_TranslateBrowsePathsToNodeIdsResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST],
                        &response, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]);
    return response;
}

UA_RegisterNodesResponse
UA_Client_Service_registerNodes(UA_Client *client,
                                const UA_RegisterNodesRequest request) {
    UA_RegisterNodesResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST],
                        &response, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]);
    return response;
}

UA_UnregisterNodesResponse
UA_Client_Service_unregisterNodes(UA_Client *client,
                                  const UA_UnregisterNodesRequest request) {
    UA_UnregisterNodesResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST],
                        &response, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]);
    return response;
}

#ifdef UA_ENABLE_QUERY

UA_QueryFirstResponse
UA_Client_Service_queryFirst(UA_Client *client,
                             const UA_QueryFirstRequest request) {
    UA_QueryFirstResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST],
                        &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]);
    return response;
}

UA_QueryNextResponse
UA_Client_Service_queryNext(UA_Client *client, const UA_QueryNextRequest request) {
    UA_QueryNextResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_QUERYNEXTREQUEST],
                        &response, &UA_TYPES[UA_TYPES_QUERYNEXTRESPONSE]);
    return response;
}

#endif

/********************/
/* Async Shorthands */
/********************/

UA_StatusCode
__UA_Client_AsyncService(UA_Client *client, const void *request,
                         const UA_DataType *requestType,
                         UA_ClientAsyncServiceCallback callback,
                         const UA_DataType *responseType,
                         void *userdata, UA_UInt32 *requestId) {
    lockClient(client);
    UA_StatusCode res =
        __Client_AsyncService(client, request, requestType, callback, responseType,
                              userdata, requestId);
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_sendAsyncReadRequest(UA_Client *client, UA_ReadRequest *request,
                               UA_ClientAsyncReadCallback readCallback,
                               void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_AsyncService(client, request, &UA_TYPES[UA_TYPES_READREQUEST],
                                    (UA_ClientAsyncServiceCallback)readCallback,
                                    &UA_TYPES[UA_TYPES_READRESPONSE], userdata, reqId);
}

UA_StatusCode
UA_Client_sendAsyncWriteRequest(UA_Client *client, UA_WriteRequest *request,
                                UA_ClientAsyncWriteCallback writeCallback,
                                void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_AsyncService(client, request, &UA_TYPES[UA_TYPES_WRITEREQUEST],
                                    (UA_ClientAsyncServiceCallback)writeCallback,
                                    &UA_TYPES[UA_TYPES_WRITERESPONSE], userdata, reqId);
}

UA_StatusCode
UA_Client_sendAsyncBrowseRequest(UA_Client *client, UA_BrowseRequest *request,
                                 UA_ClientAsyncBrowseCallback browseCallback,
                                 void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_AsyncService(client, request, &UA_TYPES[UA_TYPES_BROWSEREQUEST],
                                    (UA_ClientAsyncServiceCallback)browseCallback,
                                    &UA_TYPES[UA_TYPES_BROWSERESPONSE], userdata, reqId);
}

UA_StatusCode
UA_Client_sendAsyncBrowseNextRequest(UA_Client *client,
                                     UA_BrowseNextRequest *request,
                                     UA_ClientAsyncBrowseNextCallback browseNextCallback,
                                     void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_AsyncService(client, request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST],
                                    (UA_ClientAsyncServiceCallback)browseNextCallback,
                                    &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], userdata, reqId);
}

/**** amalgamated original file "/src/client/ua_client_connect.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017-2019 (c) Fraunhofer IOSB (Author: Mark Giraud)
 *    Copyright 2025 (c) Siemens AG (Author: Tin Raic)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */



/* Some OPC UA servers only return all Endpoints if the EndpointURL used during
 * the HEL/ACK handshake exactly matches -- including the path following the
 * address and port! Hence for the first connection we only call FindServers and
 * reopen a new TCP connection using then EndpointURL found there.
 *
 * The overall process is this:
 * - Connect with the EndpointURL provided by the user (HEL/ACK)
 * - Call FindServers
 *   - If one of the results has an exactly matching EndpointUrl, continue.
 *   - Otherwise select a matching server, update the endpointURL member of
 *     UA_Client and reconnect.
 * - Call GetEndpoints and select an Endpoint
 * - Open a SecureChannel and Session for that Endpoint
 * - Read the namespaces array of the server (and create the namespaces mapping)
 */

#define UA_MINMESSAGESIZE 8192
#define MAX_DATA_SIZE 4096

static void initConnect(UA_Client *client);
static UA_StatusCode createSessionAsync(UA_Client *client);
static UA_UserTokenPolicy *
findUserTokenPolicy(UA_Client *client, UA_EndpointDescription *endpoint,
                    char *logPrefix);

/* Get the EndpointUrl to be used right now.
 * This is adjusted during the discovery process.
 * We fall back if connecting to an EndpointUrl fails. */
static UA_String
getEndpointUrl(UA_Client *client) {
    if(client->endpoint.endpointUrl.length > 0)
        return client->endpoint.endpointUrl;
    if(client->discoveryUrl.length > 0)
        return client->discoveryUrl;
    return client->config.endpointUrl;
}

/* If an EndpointUrl doesn't work (TCP connection fails), fall back to the
 * initial EndpointUrl */
static UA_StatusCode
fallbackEndpointUrl(UA_Client* client) {
    /* Cannot fallback, the initial EndpointUrl is already in use */
    UA_String currentUrl = getEndpointUrl(client);
    if(UA_String_equal(&currentUrl, &client->config.endpointUrl)) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Could not open a TCP connection to the Endpoint at %S",
                     client->config.endpointUrl);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    if(client->endpoint.endpointUrl.length > 0) {
        /* Overwrite the EndpointUrl of the Endpoint */
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Could not open a TCP connection to the Endpoint at %S. "
                       "Overriding the endpoint description with the initial "
                       "EndpointUrl at %S.",
                       client->config.endpoint.endpointUrl,
                       client->config.endpointUrl);
        UA_String_clear(&client->endpoint.endpointUrl);
        return UA_String_copy(&client->config.endpointUrl,
                              &client->endpoint.endpointUrl);
    } else {
        /* Overwrite the DiscoveryUrl returned by FindServers */
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "The DiscoveryUrl returned by the FindServers service (%S) "
                       "could not be connected. Continuing with the initial EndpointUrl "
                       "%S for the GetEndpoints service.",
                       client->config.endpointUrl, client->config.endpointUrl);
        UA_String_clear(&client->discoveryUrl);
        return UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
    }
}

static UA_SecurityPolicy *
getSecurityPolicy(UA_Client *client, UA_String policyUri) {
    for(size_t i = 0; i < client->config.securityPoliciesSize; i++) {
        if(UA_String_equal(&policyUri, &client->config.securityPolicies[i].policyUri))
            return &client->config.securityPolicies[i];
    }
    return NULL;
}

/* Match PolicyUri and certificate. The returned SecurityPolicy instance carries
 * the private key to sign with the given ceertificate. */
static UA_SecurityPolicy *
getAuthSecurityPolicy(UA_Client *client, const UA_String policyUri,
                      const UA_ByteString certificate) {
    for(size_t i = 0; i < client->config.authSecurityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &client->config.authSecurityPolicies[i];
        if(!UA_String_equal(&policyUri, &sp->policyUri))
            continue;
        if(!UA_ByteString_equal(&certificate, &sp->localCertificate))
            continue;
        return sp;
    }
    return NULL;
}

/* The endpoint is unconfigured if the description is all zeroed-out */
static UA_Boolean
endpointUnconfigured(const UA_EndpointDescription *endpoint) {
    UA_EndpointDescription tmp;
    UA_EndpointDescription_init(&tmp);
    return UA_equal(&tmp, endpoint, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
}

UA_Boolean
isFullyConnected(UA_Client *client) {
    /* No SecureChannel */
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN)
        return false;

    /* GetEndpoints handshake ongoing or not yet done */
    if(client->endpointsHandshake || endpointUnconfigured(&client->endpoint))
        return false;

    /* FindServers handshake ongoing or not yet done */
    if(client->findServersHandshake || client->discoveryUrl.length == 0)
        return false;

    if(!client->config.noSession) {
        /* No Session, but is required */
        if(client->sessionState != UA_SESSIONSTATE_ACTIVATED)
            return false;

        /* NamespaceArray not yet read */
        if(client->namespacesHandshake || !client->haveNamespaces)
            return false;
    }

    return true;
}

static UA_StatusCode
initUserTokenPolicy(UA_Client *client, const UA_UserTokenPolicy **outUtp,
                    char *logPrefix) {
    const UA_UserTokenPolicy *utp =
        findUserTokenPolicy(client, &client->endpoint, logPrefix);
    if(!utp) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "%s: Could not find a matching UserTokenPolicy "
                     "in the endpoint", logPrefix);
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    }

    UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                "%s: Using UserTokenPolicy %S", logPrefix, utp->policyId);

    /* If not specifically defined in the UserTokenPolicy, then the
     * SecurityPolicy of the underlying endpoint (SecureChannel) is used. */
    UA_String tokenSecurityPolicyUri = (utp->securityPolicyUri.length > 0) ?
        utp->securityPolicyUri : client->endpoint.securityPolicyUri;

    /* Get the SecurityPolicy for authentication */
    UA_SecurityPolicy *utsp;
    if(utp->tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
        UA_X509IdentityToken *token = (UA_X509IdentityToken*)
            client->config.userIdentityToken.content.decoded.data;
        utsp = getAuthSecurityPolicy(client, tokenSecurityPolicyUri,
                                     token->certificateData);
    } else {
        utsp = getSecurityPolicy(client, tokenSecurityPolicyUri);
    }
    if(!utsp) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "%s: SecurityPoliocy %S not available for the "
                     "UserTokenPolicy", logPrefix, tokenSecurityPolicyUri);
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    }

    /* ExistingSecurityPolicy matches? */
    if(client->utpSp) {
        if(!UA_String_equal(&client->utpSp->policyUri,
                            &tokenSecurityPolicyUri)) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "%s: SecurityPoliocy %S cannot be instantiated. "
                         "A different SecurityPolicy %s is in place already",
                         logPrefix, tokenSecurityPolicyUri,
                         client->utpSp->policyUri);
            return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
        }

        /* Set the output and return */
        *outUtp = utp;
        return UA_STATUSCODE_GOOD;
    }

    /* Create an instance of the SecurityPolicy using the server certificate
     * from the endpoint */
    UA_StatusCode res =
        utsp->newChannelContext(utsp, &client->endpoint.serverCertificate,
                                &client->utpSpContext);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "%s: UserTokenPolicy %S could not be instantiated with the "
                     "server certificate", logPrefix, tokenSecurityPolicyUri);
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    }
    client->utpSp = utsp;

    /* Set the output and return */
    *outUtp = utp;
    return UA_STATUSCODE_GOOD;
}

/* Legacy (pre-v1.05.07) signature: the leaf of the remote (peer) certificate
 * concatenated with the server's session nonce, signed with the given
 * SecurityPolicy/context. Shared by the application ClientSignature and the
 * X.509 user-token signature. The leaf is used (not the raw, possibly-chained
 * remoteCertificate) so the bytes match the server's verify, which is computed
 * over its single localCertificate. */
static UA_StatusCode
signLegacyCertNonce(const UA_SecurityPolicy *sp, void *spContext,
                    const UA_ByteString *remoteCertificate,
                    const UA_ByteString *serverNonce, UA_ByteString *outSignature) {
    UA_ByteString leaf = getLeafCertificate(*remoteCertificate);
    size_t signDataSize = leaf.length + serverNonce->length;
    if(signDataSize > MAX_DATA_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_Byte buf[MAX_DATA_SIZE];
    UA_ByteString signData = {signDataSize, buf};
    memcpy(buf, leaf.data, leaf.length);
    memcpy(buf + leaf.length, serverNonce->data, serverNonce->length);
    return sp->asymSignatureAlgorithm.sign(sp, spContext, &signData, outSignature);
}

/* Function to create a signature using remote certificate and nonce.
 * This uses the SecurityPolicy of the SecureChannel. */
static UA_StatusCode
signClientSignature(UA_Client *client, UA_ActivateSessionRequest *request) {
    UA_SecureChannel *channel = &client->channel;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    void *cc = channel->channelContext;

    UA_SignatureData *sd = &request->clientSignature;
    const UA_SecurityPolicySignatureAlgorithm *signAlg = &sp->asymSignatureAlgorithm;

    /* OPC UA Part 4 v1.05.07: for SecurityPolicies with
     * secureChannelEnhancements = true, the algorithm field in
     * SignatureData shall be NULL or empty and receivers shall
     * ignore the value. */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(!UA_SecurityPolicy_isEnhancedSecurity(sp))
        retval = UA_String_copy(&signAlg->uri, &sd->algorithm);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Allocate memory for the signature */
    size_t signatureSize = signAlg->getLocalSignatureSize(sp, cc);
    retval = UA_ByteString_allocBuffer(&sd->signature, signatureSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(UA_SecurityPolicy_isEnhancedSecurity(sp)) {
        /* Channel-bound v1.05.07 ClientSignature (see the cert-role table at
         * UA_SecureChannel_buildActivateSessionSignatureData). */
        UA_ByteString signData = UA_BYTESTRING_NULL;
        retval = UA_SecureChannel_buildActivateSessionSignatureData(
            channel, &client->serverSessionNonce, &client->clientSessionNonce,
            &channel->remoteCertificate, &channel->remoteCertificate,
            &sp->localCertificate, &signData);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        retval = signAlg->sign(sp, cc, &signData, &sd->signature);
        UA_ByteString_clear(&signData);
        return retval;
    }

    /* Legacy (v1.05.06): leaf(serverCert) + serverNonce. */
    return signLegacyCertNonce(sp, cc, &channel->remoteCertificate,
                               &client->serverSessionNonce, &sd->signature);
}

/* This uses the SecurityPolicy of the UserTokenPolicy */
static UA_StatusCode
signUserTokenSignature(UA_Client *client,
                       UA_ActivateSessionRequest *request) {
    UA_assert(client->config.userIdentityToken.content.decoded.type ==
              &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]);

    UA_SecurityPolicy *utpSp = client->utpSp;
    UA_assert(utpSp);

    UA_SecureChannel *channel = &client->channel;
    UA_SecurityPolicySignatureAlgorithm *signAlg = &utpSp->asymSignatureAlgorithm;
    UA_SignatureData *utsd = &request->userTokenSignature;

    /* Stricter servers reject an empty user-token algorithm - so always send
     * the policy's signature URI (the AesGcm policy carries its SecurityPolicy
     * URI there; RSA carries the RSA URI; plain ECC carries an empty
     * string). */
    UA_StatusCode retval = UA_String_copy(&signAlg->uri, &utsd->algorithm);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Allocate memory for the signature */
    size_t sigLen = signAlg->getLocalSignatureSize(utpSp, client->utpSpContext);
    retval = UA_ByteString_allocBuffer(&utsd->signature, sigLen);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Channel-bound v1.05.07 user-token signature (see the cert-role table at
     * UA_SecureChannel_buildUserTokenSignatureData), produced with the user's
     * private key (utpSp context). Used only when BOTH the SecureChannel AND the
     * user-token SecurityPolicy are enhanced; a legacy RSA / old-ECC user token
     * uses the legacy layout even over an enhanced (AesGcm) SecureChannel. */
    if(UA_SecurityPolicy_isEnhancedSecurity(channel->securityPolicy) &&
       UA_SecurityPolicy_isEnhancedSecurity(utpSp)) {
        const UA_ByteString *clientCert = &channel->securityPolicy->localCertificate;
        UA_ByteString signData = UA_BYTESTRING_NULL;
        retval = UA_SecureChannel_buildUserTokenSignatureData(
            channel, &client->serverSessionNonce, &client->clientSessionNonce,
            &channel->remoteCertificate, &channel->remoteCertificate,
            clientCert, clientCert, &signData);
        if(retval == UA_STATUSCODE_GOOD)
            retval = signAlg->sign(utpSp, client->utpSpContext, &signData, &utsd->signature);
        UA_ByteString_clear(&signData);
        return retval;
    }

    /* Legacy (v1.05.06): leaf(serverCert) + serverNonce (same as the
     * application ClientSignature), signed with the user's key. */
    return signLegacyCertNonce(utpSp, client->utpSpContext,
                               &channel->remoteCertificate,
                               &client->serverSessionNonce, &utsd->signature);
}

/* UserName and IssuedIdentity can be encrypted. This uses the SecurityPolicy
 * instance for the UserTokenPolicy. So it can keep the ECC ephemeral keys
 * across multiple SecureChannels. */
static UA_StatusCode
encryptUserIdentityToken(UA_Client *client, UA_ExtensionObject *userIdentityToken) {
    UA_IssuedIdentityToken *iit = NULL;
    UA_UserNameIdentityToken *unit = NULL;
    UA_String *encryptionAlg;
    UA_ByteString *tokenData;

    const UA_DataType *tokenType = userIdentityToken->content.decoded.type;
    if(tokenType == &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN]) {
        iit = (UA_IssuedIdentityToken*)userIdentityToken->content.decoded.data;
        tokenData = &iit->tokenData;
        encryptionAlg = &iit->encryptionAlgorithm;
    } else { /* tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN] */
        UA_assert(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]);
        unit = (UA_UserNameIdentityToken*)userIdentityToken->content.decoded.data;
        tokenData = &unit->password;
        encryptionAlg = &unit->encryptionAlgorithm;
    }

    /* The sessionSp is instantiated during CreateSession */
    UA_SecurityPolicy *utpSp = client->utpSp;
    UA_assert(utpSp);

    /* Nothing to encrypt */
    if(utpSp->policyType == UA_SECURITYPOLICYTYPE_NONE) {
        /* Warn if a token is transmitted in cleartext. This needs to be allowed
         * with the allowNonePolicyPassword setting and is checked in
         * findUserTokenPolicy. */
        if(client->channel.securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "!!! Warning !!! AuthenticationToken is transmitted "
                           "without encryption");
        return UA_STATUSCODE_GOOD;
    }

    /* Encrypt the TokenData */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(UA_SecurityPolicy_isEcc(utpSp)) {
        res = encryptUserIdentityTokenEcc(client->config.logging, &client->channel,
                                          utpSp, client->utpSpContext, tokenData,
                                          client->serverSessionNonce,
                                          client->serverEphemeralPubKey);
        /* Don't reuse the Ephemeral Public Key */
        UA_ByteString_clear(&client->serverEphemeralPubKey);

        /* The EccEncryptedSecret identifies its algorithm via the SecurityPolicy
         * URI embedded in the secret header, so the UserIdentityToken's
         * encryptionAlgorithm field is left EMPTY (matching the OPC UA reference
         * stack, which sets it to null for the EncryptedSecret format). Sending
         * the policy's asymEncryptionAlgorithm URI here makes strict servers
         * reject the token with BadIdentityTokenInvalid */
        return res;
    }

    res = encryptSecretLegacy(utpSp, client->utpSpContext,
                              client->serverSessionNonce, tokenData);

    /* Legacy RSA EncryptedData: carry the asymmetric encryption algorithm URI */
    return res | UA_String_copy(&utpSp->asymEncryptionAlgorithm.uri, encryptionAlg);
}

/* Verifies the signature corresponds to ClientNonce using the SecurityPolicy of
 * the SecureChannel */
static UA_StatusCode
checkCreateSessionSignature(UA_Client *client, const UA_SecureChannel *channel,
                            const UA_CreateSessionResponse *response) {
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    if(!channel->securityPolicy)
        return UA_STATUSCODE_BADINTERNALERROR;

    const UA_SecurityPolicy *sp = channel->securityPolicy;
    const UA_ByteString *lc = &sp->localCertificate;

    UA_ByteString dataToVerify = UA_BYTESTRING_NULL;
    UA_StatusCode retval;
    if(UA_SecurityPolicy_isEnhancedSecurity(sp)) {
        /* Channel-bound v1.05.07 CreateSession ServerSignature (see the
         * cert-role table at UA_SecureChannel_buildCreateSessionSignatureData). */
        retval = UA_SecureChannel_buildCreateSessionSignatureData(
            channel, &client->clientSessionNonce, &response->serverNonce,
            &channel->remoteCertificate, lc, &dataToVerify);
    } else {
        retval = UA_ByteString_allocBuffer(&dataToVerify,
                                           lc->length + client->clientSessionNonce.length);
        if(retval == UA_STATUSCODE_GOOD) {
            memcpy(dataToVerify.data, lc->data, lc->length);
            memcpy(dataToVerify.data + lc->length, client->clientSessionNonce.data,
                   client->clientSessionNonce.length);
        }
    }
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    const UA_SecurityPolicySignatureAlgorithm *signAlg = &sp->asymSignatureAlgorithm;
    retval = signAlg->verify(sp, channel->channelContext, &dataToVerify,
                             &response->serverSignature.signature);
    UA_ByteString_clear(&dataToVerify);
    return retval;
}

/***********************/
/* Open the Connection */
/***********************/

void
processERRResponse(UA_Client *client, const UA_ByteString *chunk) {
    size_t offset = 0;
    UA_TcpErrorMessage errMessage;
    UA_StatusCode res =
        UA_decodeBinaryInternal(chunk, &offset, &errMessage,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                             "Received an ERR response that could not be decoded "
                             "with StatusCode %s", UA_StatusCode_name(res));
        setConnectStatus(client, res);
        return;
    }

    UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                         "Received an ERR response with StatusCode %s and "
                         "the following reason: \"%S\"",
                         UA_StatusCode_name(errMessage.error),
                         errMessage.reason);
    setConnectStatus(client, errMessage.error);
    UA_TcpErrorMessage_clear(&errMessage);
}

void
processACKResponse(UA_Client *client, const UA_ByteString *chunk) {
    UA_SecureChannel *channel = &client->channel;
    if(channel->state != UA_SECURECHANNELSTATE_HEL_SENT) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, channel,
                             "SecureChannel not in the HEL-sent state");
        setConnectStatus(client, UA_STATUSCODE_BADSECURECHANNELCLOSED);
        return;
    }

    /* Decode the message */
    size_t offset = 0;
    UA_TcpAcknowledgeMessage ackMessage;
    UA_StatusCode res =
        UA_decodeBinaryInternal(chunk, &offset, &ackMessage,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_NETWORK,
                     "Decoding ACK message failed");
        setConnectStatus(client, res);
        return;
    }

    res = UA_SecureChannel_processHELACK(channel, &ackMessage);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_NETWORK,
                     "Processing the ACK message failed with StatusCode %s",
                     UA_StatusCode_name(res));
        setConnectStatus(client, res);
        return;
    }

    client->channel.state = UA_SECURECHANNELSTATE_ACK_RECEIVED;
}

static UA_StatusCode
sendHELMessage(UA_Client *client) {
    UA_ConnectionManager *cm = client->channel.connectionManager;
    if(!UA_SecureChannel_isConnected(&client->channel))
        return UA_STATUSCODE_BADNOTCONNECTED;

    /* Get a buffer */
    UA_ByteString message;
    UA_StatusCode retval = cm->allocNetworkBuffer(cm, client->channel.connectionId,
                                                  &message, UA_MINMESSAGESIZE);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Prepare the HEL message and encode at offset 8 */
    UA_TcpHelloMessage hello;
    hello.protocolVersion = 0;
    hello.receiveBufferSize = client->config.localConnectionConfig.recvBufferSize;
    hello.sendBufferSize = client->config.localConnectionConfig.sendBufferSize;
    hello.maxMessageSize = client->config.localConnectionConfig.localMaxMessageSize;
    hello.maxChunkCount = client->config.localConnectionConfig.localMaxChunkCount;
    hello.endpointUrl = getEndpointUrl(client);

    UA_Byte *bufPos = &message.data[8]; /* skip the header */
    const UA_Byte *bufEnd = &message.data[message.length];
    retval = UA_encodeBinaryInternal(&hello, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE],
                                     &bufPos, &bufEnd, NULL, NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, client->channel.connectionId, &message);
        return retval;
    }

    /* Encode the message header at offset 0 */
    UA_TcpMessageHeader messageHeader;
    messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_HEL;
    messageHeader.messageSize = (UA_UInt32) ((uintptr_t)bufPos - (uintptr_t)message.data);
    bufPos = message.data;
    retval = UA_encodeBinaryInternal(&messageHeader,
                                     &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                     &bufPos, &bufEnd, NULL, NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, client->channel.connectionId, &message);
        return retval;
    }

    /* Send the HEL message */
    message.length = messageHeader.messageSize;
    retval = cm->sendWithConnection(cm, client->channel.connectionId,
                                    &UA_KEYVALUEMAP_NULL, &message);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Sending HEL failed");
        setConnectStatus(client, retval);
        return retval;
    }

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Sent HEL message");

    client->channel.state = UA_SECURECHANNELSTATE_HEL_SENT;
    return UA_STATUSCODE_GOOD;
}

void processRHEMessage(UA_Client *client, const UA_ByteString *chunk) {
    UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT, "RHE received");

    size_t offset = 0; /* Go to the beginning of the TcpHelloMessage */
    UA_TcpReverseHelloMessage rheMessage;
    static const UA_DataType *rheType = &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE];
    UA_StatusCode res = UA_decodeBinaryInternal(chunk, &offset, &rheMessage, rheType, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
                     "Decoding RHE message failed");
        setConnectStatus(client, res);
        return;
    }

    /* Set the internal DisocveryUrl */
    UA_String_clear(&client->discoveryUrl);
    client->discoveryUrl = rheMessage.endpointUrl;
    UA_String_init(&rheMessage.endpointUrl);
    UA_TcpReverseHelloMessage_clear(&rheMessage);

    /* Send the HEL message */
    setConnectStatus(client, sendHELMessage(client));
}

void
processOPNResponse(UA_Client *client, const UA_ByteString *message) {
    size_t offset = 0;
    UA_NodeId responseId;
    UA_OpenSecureChannelResponse response;
    UA_NodeId expectedId = UA_NS0ID(OPENSECURECHANNELRESPONSE_ENCODING_DEFAULTBINARY);

    /* Decode the type NodeId */
    UA_StatusCode res = UA_NodeId_decodeBinary(message, &offset, &responseId);
    if(res != UA_STATUSCODE_GOOD)
        goto finish_decode;

    /* Is the response of the expected type? */
    if(!UA_NodeId_equal(&responseId, &expectedId)) {
        res = UA_STATUSCODE_BADDECODINGERROR;
        goto finish_decode;
    }

    /* Decode the response */
    res = UA_decodeBinaryInternal(message, &offset, &response,
                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE], NULL);

    finish_decode:
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                             "Could not decode the OpenSecureChannelResponse");
        setConnectStatus(client, res);
        return;
    }

    /* Check whether the nonce was reused */
    if(client->channel.securityMode != UA_MESSAGESECURITYMODE_NONE &&
       UA_ByteString_equal(&client->channel.remoteNonce, &response.serverNonce)) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                             "The server reused the last nonce");
        setConnectStatus(client, UA_STATUSCODE_BADSECURITYCHECKSFAILED);
        return;
    }

    /* Check the nonce length */
    if(response.serverNonce.length < client->channel.securityPolicy->nonceLength) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                             "The server nonce is too short");
        setConnectStatus(client, UA_STATUSCODE_BADSECURITYCHECKSFAILED);
        return;
    }

    /* Move the nonce out of the response */
    UA_ByteString_clear(&client->channel.remoteNonce);
    client->channel.remoteNonce = response.serverNonce;
    UA_ByteString_init(&response.serverNonce);
    UA_ResponseHeader_clear(&response.responseHeader);

    /* Replace the token. Keep the current token as the old token. Messages
     * might still arrive for the old token. */
    client->channel.altSecurityToken = client->channel.securityToken;
    client->channel.securityToken = response.securityToken;
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT;

    /* Log a warning if the SecurityToken is not "fresh". Use the normal system
     * clock to do the comparison. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime wallClockNow = el->dateTime_now(el);
    UA_ChannelSecurityToken *st = &client->channel.securityToken;
    if(wallClockNow - st->createdAt >= UA_DATETIME_SEC * 10 ||
       wallClockNow - st->createdAt <= -UA_DATETIME_SEC * 10)
        UA_LOG_WARNING_CHANNEL(client->config.logging, &client->channel,
                               "The \"CreatedAt\" timestamp of the received "
                               "ChannelSecurityToken does not match "
                               "with the local system clock");

    /* The internal "monotonic" clock is used by the SecureChannel to validate
     * that the SecurityToken is still valid. The monotonic clock is independent
     * from the system clock getting changed or synchronized to a master clock
     * during runtime. */
    client->channel.securityToken.createdAt = el->dateTime_nowMonotonic(el);

    /* Response.securityToken.revisedLifetime is UInt32, we need to cast it to
     * DateTime=Int64. After 75% of the lifetime the renewal takes place as
     * described in standard */
    client->nextChannelRenewal = client->channel.securityToken.createdAt +
        (UA_DateTime) (response.securityToken.revisedLifetime *
                       (UA_Double) UA_DATETIME_MSEC * 0.75);

    /* Compute the new local keys. The remote keys are updated when a message
     * with the new SecurityToken is received. */
    res = UA_SecureChannel_generateLocalKeys(&client->channel);
    if(res != UA_STATUSCODE_GOOD) {
        setConnectStatus(client, res);
        return;
    }

    UA_Float lifetime = (UA_Float)response.securityToken.revisedLifetime / 1000;
    UA_Boolean renew = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    if(renew) {
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel, "SecureChannel "
                            "renewed with a revised lifetime of %.2fs", lifetime);
    } else {
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel,
                            "SecureChannel opened with SecurityMode %s for "
                            "SecurityPolicy %S and a revised lifetime of %.2fs",
                            securityModeNames[client->channel.securityMode],
                            client->channel.securityPolicy->policyUri,
                            lifetime);
    }

    client->channel.state = UA_SECURECHANNELSTATE_OPEN;
}

/* OPN messges to renew the channel are sent asynchronous */
static UA_StatusCode
sendOPNAsync(UA_Client *client, UA_Boolean renew) {
    if(!UA_SecureChannel_isConnected(&client->channel))
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode res = UA_SecureChannel_generateLocalNonce(&client->channel);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_EventLoop *el = client->config.eventLoop;

    /* Prepare the OpenSecureChannelRequest */
    UA_OpenSecureChannelRequest opnSecRq;
    UA_OpenSecureChannelRequest_init(&opnSecRq);
    opnSecRq.requestHeader.timestamp = el->dateTime_now(el);
    opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
    opnSecRq.securityMode = client->channel.securityMode;
    opnSecRq.clientNonce = client->channel.localNonce;
    opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
    if(renew) {
        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                             "Requesting to renew the SecureChannel");
    } else {
        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                             "Requesting to open a SecureChannel");
    }

    /* Prepare the entry for the linked list */
    UA_UInt32 requestId = ++client->requestId;

    /* Send the OPN message */
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
                 "Requesting to open a SecureChannel");
    static const UA_DataType *opnReqType = &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST];
    res = UA_SecureChannel_sendOPN(&client->channel, requestId, &opnSecRq, opnReqType);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
                      "Sending OPN message failed with error %s",
                      UA_StatusCode_name(res));
        return res;
    }

    /* Update the state */
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_SENT;
    if(client->channel.state < UA_SECURECHANNELSTATE_OPN_SENT)
        client->channel.state = UA_SECURECHANNELSTATE_OPN_SENT;

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
                 "OPN message sent");

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
__Client_renewSecureChannel(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime now = el->dateTime_nowMonotonic(el);

    /* Check if OPN has been sent or the SecureChannel is still valid */
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN ||
       client->channel.renewState == UA_SECURECHANNELRENEWSTATE_SENT ||
       client->nextChannelRenewal > now)
        return UA_STATUSCODE_GOODCALLAGAIN;

    UA_StatusCode res = sendOPNAsync(client, true);
    setConnectStatus(client, res);

    return res;
}

UA_StatusCode
UA_Client_renewSecureChannel(UA_Client *client) {
    lockClient(client);
    UA_StatusCode res = __Client_renewSecureChannel(client);
    unlockClient(client);
    return res;
}

static void
responseReadNamespacesArray(UA_Client *client, void *userdata,
                            UA_UInt32 requestId, void *response) {
    client->namespacesHandshake = false;
    client->haveNamespaces = true;

    UA_ReadResponse *resp = (UA_ReadResponse *)response;

    /* Add received namespaces to the local array. */
    if(!resp->results || !resp->results[0].value.data) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "No result in the read namespace array response");
        return;
    }
    UA_String *ns = (UA_String *)resp->results[0].value.data;
    size_t nsSize = resp->results[0].value.arrayLength;
    UA_String_copy(&ns[1], &client->namespaces[1]);
    for(size_t i = 2; i < nsSize; ++i) {
        UA_UInt16 nsIndex = 0;
        UA_Client_addNamespace(client, ns[i], &nsIndex);
    }

    /* Set up the mapping. */
    UA_NamespaceMapping *nsMapping = (UA_NamespaceMapping*)
        UA_calloc(1, sizeof(UA_NamespaceMapping));
    if(!nsMapping) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Namespace mapping creation failed. Out of Memory.");
        return;
    }
    UA_StatusCode retval =
        UA_Array_copy(client->namespaces, client->namespacesSize,
                      (void**)&nsMapping->namespaceUris,
                      &UA_TYPES[UA_TYPES_STRING]);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Failed to copy the namespaces with StatusCode %s.",
                     UA_StatusCode_name(retval));
        UA_NamespaceMapping_delete(nsMapping);
        return;
    }
    nsMapping->namespaceUrisSize = client->namespacesSize;

    nsMapping->remote2local = (UA_UInt16*)UA_calloc( nsSize, sizeof(UA_UInt16));
    if(!nsMapping->remote2local) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Namespace mapping creation failed. Out of Memory.");
        UA_NamespaceMapping_delete(nsMapping);
        return;
    }
    nsMapping->remote2localSize = nsSize;
    nsMapping->remote2local[0] = 0;
    nsMapping->remote2local[1] = 1;

    for(size_t i = 2; i < nsSize; ++i) {
        UA_UInt16 nsIndex = 0;
        UA_Client_getNamespaceIndex(client, ns[i], &nsIndex);
        nsMapping->remote2local[i] = nsIndex;
    }

    size_t l2rSize = client->namespacesSize > nsSize ? client->namespacesSize : nsSize;
    nsMapping->local2remote = (UA_UInt16*)UA_calloc(l2rSize, sizeof(UA_UInt16));
    if(!nsMapping->local2remote) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Namespace mapping creation failed. Out of Memory.");
        UA_NamespaceMapping_delete(nsMapping);
        return;
    }
    nsMapping->local2remoteSize = l2rSize;
    nsMapping->local2remote[0] = 0;
    nsMapping->local2remote[1] = 1;

    for(size_t i = 2; i < nsMapping->remote2localSize; ++i) {
        UA_UInt16 localIndex = nsMapping->remote2local[i];
        nsMapping->local2remote[localIndex] = (UA_UInt16)i;
    }

    client->channel.namespaceMapping = nsMapping;
}

/* We read the namespaces right after the session has opened. The user might
 * already requests other services in parallel. That leaves a short time where
 * requests can be made before the namespace mapping is configured. */
static void
readNamespacesArrayAsync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Check the connection status */
    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Cannot read the namespaces array, session neither created nor "
                     "activated. Actual state: '%u'", client->sessionState);
        return;
    }

    /* Set up the read request */
    UA_ReadRequest rr;
    UA_ReadRequest_init(&rr);

    UA_ReadValueId nodesToRead;
    UA_ReadValueId_init(&nodesToRead);
    nodesToRead.nodeId = UA_NS0ID(SERVER_NAMESPACEARRAY);
    nodesToRead.attributeId = UA_ATTRIBUTEID_VALUE;

    rr.nodesToRead = &nodesToRead;
    rr.nodesToReadSize = 1;

    /* Send the async read request */
    UA_StatusCode res =
        __Client_AsyncService(client, &rr, &UA_TYPES[UA_TYPES_READREQUEST],
                              (UA_ClientAsyncServiceCallback)responseReadNamespacesArray,
                              &UA_TYPES[UA_TYPES_READRESPONSE],
                              NULL, NULL);

    if(res == UA_STATUSCODE_GOOD)
        client->namespacesHandshake = true;
    else
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Could not read the namespace array with error code %s",
                     UA_StatusCode_name(res));
}

static void
extractEphemeralKeyFromAddHeader(UA_Client *client, UA_ExtensionObject *ah) {
    const UA_DataType *ahType = &UA_TYPES[UA_TYPES_ADDITIONALPARAMETERSTYPE];
    if(!UA_ExtensionObject_hasDecodedType(ah, ahType))
        return;

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SESSION,
                 "Server Ephemeral Key in the response");

    /* KeyValueMap has the identical structure the UA_AdditionalParametersType */
    UA_KeyValueMap *map = (UA_KeyValueMap*)ah->content.decoded.data;

    /* TODO: Handle the ECDHPolicyUri */

    /* Get the Ephemeral Key */
    UA_EphemeralKeyType *ephKey = (UA_EphemeralKeyType*)(uintptr_t)
        UA_KeyValueMap_getScalar(map, UA_QUALIFIEDNAME(0, "ECDHKey"),
                                 &UA_TYPES[UA_TYPES_EPHEMERALKEYTYPE]);
    if(!ephKey)
        return; /* TODO: Security error? */

    /* Move the Ephemeral Key into the client */
    UA_ByteString_clear(&client->serverEphemeralPubKey);
    client->serverEphemeralPubKey = ephKey->publicKey;
    UA_ByteString_init(&ephKey->publicKey);

    /* TODO: Validate the signature of the ephemeral key */
}

static void
responseActivateSession(UA_Client *client, void *userdata,
                        UA_UInt32 requestId, void *response) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_ActivateSessionResponse *ar = (UA_ActivateSessionResponse*)response;
    if(ar->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        /* Activating the Session failed */
        cleanupSession(client);

        /* Configuration option to not create a new Session */
        if(client->config.noNewSession) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Session cannot be activated with StatusCode %s. "
                         "The client is configured not to create a new Session.",
                         UA_StatusCode_name(ar->responseHeader.serviceResult));
            setConnectStatus(client, ar->responseHeader.serviceResult);
            return;
        }

        /* The Session is no longer usable. Create a brand new one. */
        if(ar->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONIDINVALID ||
           ar->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Session to be activated no longer exists. Create a new Session.");
            setConnectStatus(client, createSessionAsync(client));
            return;
        }

        /* Something else is wrong. Maybe the credentials no longer work. Give up. */
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Session cannot be activated with StatusCode %s. "
                     "The client cannot recover from this, closing the connection.",
                     UA_StatusCode_name(ar->responseHeader.serviceResult));
        setConnectStatus(client, ar->responseHeader.serviceResult);
        return;
    }

    /* Check the (session) nonce length. The session nonce is the application
     * nonce (>= 32 bytes), independent of the SecurityPolicy's SecureChannel
     * nonce length (e.g. the 64-byte ECC ephemeral key). */
    if(ar->serverNonce.length < 32) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Session cannot be activated with a nonce "
                     "that is too short");
        setConnectStatus(client, UA_STATUSCODE_BADSECURITYCHECKSFAILED);
        return;
    }

    /* Replace the nonce */
    UA_ByteString_clear(&client->serverSessionNonce);
    client->serverSessionNonce = ar->serverNonce;
    UA_ByteString_init(&ar->serverNonce);

    /* Extract the server's ECC ephemeral public key from the ActivateSession
     * response */
    extractEphemeralKeyFromAddHeader(client, &ar->responseHeader.additionalHeader);

    client->sessionState = UA_SESSIONSTATE_ACTIVATED;
    notifyClientState(client);

    /* Read the namespaces array if we don't already have it */
    if(!client->haveNamespaces)
        readNamespacesArrayAsync(client);

    /* Immediately check if publish requests are outstanding - for example when
     * an existing Session has been reattached / activated. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    __Client_Subscriptions_backgroundPublish(client);
#endif
}

static UA_StatusCode
activateSessionAsync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* We should not try to activate in the current state */
    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Can not activate session, session neither created nor activated. "
                     "Actual state: '%u'", client->sessionState);
        return UA_STATUSCODE_BADSESSIONCLOSED;
    }

    /* Select the UserTokenPolicy based on the client configuration and the
     * endpoint information. Also instantiates the UserTokenPolicy if not
     * already there. This can happen when an existing Session is
     * transferred. */
    const UA_UserTokenPolicy *utp = NULL;
    UA_StatusCode retval = initUserTokenPolicy(client, &utp, "ActivateSession");
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Initialize the request */
    UA_ActivateSessionRequest request;
    UA_ActivateSessionRequest_init(&request);

    /* Set the requested LocaleIds */
    if(client->config.sessionLocaleIdsSize && client->config.sessionLocaleIds) {
        retval = UA_Array_copy(client->config.sessionLocaleIds,
                               client->config.sessionLocaleIdsSize,
                               (void **)&request.localeIds, &UA_TYPES[UA_TYPES_LOCALEID]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        request.localeIdsSize = client->config.sessionLocaleIdsSize;
    }

    /* Set the User Identity Token. If not defined use an anonymous token. Use
     * the PolicyId from the UserTokenPolicy. All token types have the PolicyId
     * string as the first element. */
    UA_AnonymousIdentityToken anonToken;
    retval = UA_ExtensionObject_copy(&client->config.userIdentityToken,
                                     &request.userIdentityToken);
    if(request.userIdentityToken.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
        UA_String *policyId = (UA_String*)request.userIdentityToken.content.decoded.data;
        UA_String_clear(policyId);
        retval = UA_String_copy(&utp->policyId, policyId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_ActivateSessionRequest_clear(&request);
            return retval;
        }
    } else {
        UA_AnonymousIdentityToken_init(&anonToken);
        UA_ExtensionObject_setValueNoDelete(&request.userIdentityToken, &anonToken,
                                            &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]);
        anonToken.policyId = utp->policyId;
    }

    switch(utp->tokenType) {
    case UA_USERTOKENTYPE_ANONYMOUS:
        break; /* The anonymous token is not encrypted */
    case UA_USERTOKENTYPE_USERNAME:
    case UA_USERTOKENTYPE_ISSUEDTOKEN:
        /* Encrypt the UserIdentityToken */
        retval = encryptUserIdentityToken(client, &request.userIdentityToken);
        break;
    case UA_USERTOKENTYPE_CERTIFICATE:
        /* Create the UserTokenSignature */
        retval = signUserTokenSignature(client, &request);
        break;
    default:
        retval = UA_STATUSCODE_BADINTERNALERROR;
    }
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ActivateSessionRequest_clear(&request);
        return retval;
    }

    /* Create the client signature with the SecurityPolicy of the SecureChannel */
    UA_SecureChannel *channel = &client->channel;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        retval |= signClientSignature(client, &request);

    /* Send the request */
    if(UA_LIKELY(retval == UA_STATUSCODE_GOOD))
        retval = __Client_AsyncService(client, &request,
                                       &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
                                       (UA_ClientAsyncServiceCallback)responseActivateSession,
                                       &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE],
                                       NULL, NULL);

    /* On success, advance the session state */
    if(retval == UA_STATUSCODE_GOOD)
        client->sessionState = UA_SESSIONSTATE_ACTIVATE_REQUESTED;
    else
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "ActivateSession failed when sending the request with error code %s",
                     UA_StatusCode_name(retval));

    /* Clean up */
    UA_ActivateSessionRequest_clear(&request);
    return retval;
}

static const UA_String binaryTransport =
    UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");

/* Find a matching endpoint -- the UserTokenPolicy is matched later */
static UA_Boolean
matchEndpoint(UA_Client *client, const UA_EndpointDescription *endpoint, unsigned i) {
    /* Matching ApplicationUri if defined */
    if(client->config.applicationUri.length > 0 &&
       !UA_String_equal(&client->config.applicationUri,
                        &endpoint->server.applicationUri)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u: Rejected, the server's ApplicationUri %S "
                    "does not match the client configuration", i,
                    endpoint->server.applicationUri);
        return false;
    }

    /* Look out for binary transport endpoints.
     * Note: Siemens returns empty ProfileUrl, we will accept it as binary. */
    if(endpoint->transportProfileUri.length != 0 &&
       !UA_String_equal(&endpoint->transportProfileUri, &binaryTransport)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u: Rejected, the TransportProfileUri %S "
                    "is not supported", i, endpoint->transportProfileUri);
        return false;
    }

    /* Valid SecurityMode? */
    if(endpoint->securityMode < 1 || endpoint->securityMode > 3) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u: Rejected, invalid SecurityMode %u",
                    i, (unsigned)endpoint->securityMode);
        return false;
    }

    UA_MessageSecurityMode configuredSM = client->config.securityMode;
    if(configuredSM > UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Bad SecurityMode set in the client config");
        return false;
    }

    /* Selected SecurityMode? */
    if(configuredSM > 0 && configuredSM != endpoint->securityMode) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u: Rejected, the SecurityMode %s "
                    "does not match the client configuration (%s)",
                    i, securityModeNames[endpoint->securityMode],
                    securityModeNames[configuredSM]);
        return false;
    }

    /* Matching SecurityPolicy? */
    if(client->config.securityPolicyUri.length > 0 &&
       !UA_String_equal(&client->config.securityPolicyUri,
                        &endpoint->securityPolicyUri)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u: Rejected, the SecurityPolicy %S does not "
                    "match the configuration", i, endpoint->securityPolicyUri);
        return false;
    }

    /* SecurityPolicy available? */
    if(!getSecurityPolicy(client, endpoint->securityPolicyUri)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u: Rejected, the SecurityPolicy %S not supported",
                    i, endpoint->securityPolicyUri);
        return false;
    }

    return true;
}

/* Match the policy with the configured user token */
static UA_Boolean
matchUserToken(UA_Client *client,
               const UA_UserTokenPolicy *tokenPolicy) {
    const UA_DataType *tokenType =
        client->config.userIdentityToken.content.decoded.type;

    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_ANONYMOUS &&
       (tokenType == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] || !tokenType))
        return true;

    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_USERNAME &&
       tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])
        return true;

    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_CERTIFICATE &&
       tokenType == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN])
        return true;

    if(tokenPolicy->tokenType == UA_USERTOKENTYPE_ISSUEDTOKEN &&
       tokenType == &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN])
        return true;

    return false;
}

static UA_Boolean
matchUserTokenPolicy(UA_Client *client, UA_EndpointDescription *endpoint,
                     UA_UserTokenPolicy *utp, char *logPrefix) {
    /* Match with the configured UserToken */
    if(!matchUserToken(client, utp)) {
        if(logPrefix) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "%s: UserTokenPolicy %S rejected -- does not match "
                        "the type of UserIdentityToken configured in the client",
                        logPrefix, utp->policyId);
        }
        return false;
    }

    /* If not defined, use the SecurityPolicy of the SecureChannel */
    UA_String tokenPolicyUri =
        (UA_String_isEmpty(&utp->securityPolicyUri)) ?
        endpoint->securityPolicyUri : utp->securityPolicyUri;

    /* SecurityPolicyUri matches the configuration? */
    if(!UA_String_isEmpty(&client->config.authSecurityPolicyUri) &&
       !UA_String_equal(&client->config.authSecurityPolicyUri,
                        &tokenPolicyUri)) {
        if(logPrefix) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "%s: UserTokenPolicy %S rejected -- uses SecurityPolicy %S, "
                        "but the client configuration requires SecurityPolicy %S",
                        logPrefix, utp->policyId,
                        tokenPolicyUri, client->config.authSecurityPolicyUri);
        }
        return false;
    }

    /* Anoymous authentication */
    if(utp->tokenType == UA_USERTOKENTYPE_ANONYMOUS)
        return true;

    /* Get the SecurityPolicy */
    UA_SecurityPolicy *utsp;
    if(utp->tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
        UA_X509IdentityToken *token = (UA_X509IdentityToken*)
            client->config.userIdentityToken.content.decoded.data;
        utsp = getAuthSecurityPolicy(client, tokenPolicyUri,
                                     token->certificateData);
    } else {
        utsp = getSecurityPolicy(client, tokenPolicyUri);
    }
    if(!utsp) {
        if(logPrefix) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "%s: UserTokenPolicy %S rejected -- the "
                        "SecurityPolicy %S is not available",
                        logPrefix, utp->policyId, tokenPolicyUri);
        }
        return false;
    }

    /* Check if a secret is transmitted in cleartext */
    if(endpoint->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
       utsp->policyType == UA_SECURITYPOLICYTYPE_NONE) {
        if(!client->config.allowNonePolicyPassword) {
            if(logPrefix) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "%s: UserTokenPolicy %S rejected -- the "
                            "AuthenticationToken must not be transmitted "
                            "without encryption (override with"
                            "allowNonePolicyPassword setting)",
                            logPrefix, utp->policyId);
            }
            return false;
        }
    }

    /* Found a match */
    return true;
}

/* Returns a matching UserTokenPolicy from the EndpointDescription. If a
 * UserTokenPolicy is configured in the client config, then we need an exact
 * match. */
static UA_UserTokenPolicy *
findUserTokenPolicy(UA_Client *client, UA_EndpointDescription *endpoint,
                    char *logPrefix) {
    /* Was a UserTokenPolicy configured? Then we need an exact match. */
    UA_UserTokenPolicy *requiredTokenPolicy = NULL;
    UA_UserTokenPolicy tmp;
    UA_UserTokenPolicy_init(&tmp);
    if(!UA_equal(&tmp, &client->config.userTokenPolicy,
                 &UA_TYPES[UA_TYPES_USERTOKENPOLICY]))
        requiredTokenPolicy = &client->config.userTokenPolicy;

    /* Return the first UserTokenPolicy matching the config */
    for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) {
        UA_UserTokenPolicy *tokenPolicy = &endpoint->userIdentityTokens[j];

        /* Need the extact configured policy */
        if(requiredTokenPolicy &&
           !UA_equal(requiredTokenPolicy, tokenPolicy,
                     &UA_TYPES[UA_TYPES_USERTOKENPOLICY])) {
            if(logPrefix) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "%s: UserTokenPolicy %S rejected -- a different "
                            "UserTokenPolicy %S is specified in the client config",
                            logPrefix, tokenPolicy->policyId,
                            requiredTokenPolicy->policyId);
            }
            continue;
        }

        /* Match with the client configured */
        if(matchUserTokenPolicy(client, endpoint, tokenPolicy, logPrefix))
            return tokenPolicy;
    }

    return NULL;
}

/* Combination of UA_Client_getEndpointsInternal and getEndpoints */
static void
responseGetEndpoints(UA_Client *client, void *userdata,
                     UA_UInt32 requestId, void *response) {
    UA_LOCK_ASSERT(&client->clientMutex);

    client->endpointsHandshake = false;

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Received GetEndpointsResponse");

    UA_GetEndpointsResponse *resp = (UA_GetEndpointsResponse*)response;

    /* GetEndpoints not possible. Fail the connection */
    if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        /* Fail the connection attempt if the SecureChannel is still connected.
         * If the SecureChannel is (intentionally or unintentionally) closed,
         * the connectStatus should come from there. */
        if(UA_SecureChannel_isConnected(&client->channel)) {
           UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "GetEndpointRequest failed with error code %s",
                        UA_StatusCode_name(resp->responseHeader.serviceResult));
           setConnectStatus(client, resp->responseHeader.serviceResult);
        }

        UA_GetEndpointsResponse_clear(resp);
        return;
    }

    /* Warn if the Endpoints look incomplete / don't match the EndpointUrl */
    Client_warnEndpointsResult(client, resp, &client->discoveryUrl);

    const size_t notFound = (size_t)-1;
    size_t bestEndpointIndex = notFound;
    UA_Byte bestEndpointLevel = 0;
    UA_UserTokenPolicy *utp = NULL;

    /* Find a matching combination of Endpoint and UserTokenPolicy */
    for(size_t i = 0; i < resp->endpointsSize; ++i) {
        UA_EndpointDescription* endpoint = &resp->endpoints[i];

        /* Do we already have a better candidate? */
        if(endpoint->securityLevel < bestEndpointLevel) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Endpoint %u: Rejected, better SecurityLevel found before",
                        (unsigned)i);
            continue;
        }

        /* Does the endpoint match the client configuration? */
        if(!matchEndpoint(client, endpoint, (unsigned)i))
            continue;

        /* Do we want a session? If yes, then the endpoint needs to have a
         * UserTokenPolicy that matches the configuration. */
        if(!client->config.noSession) {
            char logPrefix[32];
            mp_snprintf(logPrefix, 32, "Endpoint %u", (unsigned)i);
            utp = findUserTokenPolicy(client, endpoint, logPrefix);
            if(!utp) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "Endpoint %u: Rejected, no matching UserTokenPolicy",
                            (unsigned)i);
                continue;
            }
        }

        /* Best endpoint so far */
        bestEndpointLevel = endpoint->securityLevel;
        bestEndpointIndex = i;
        if(utp) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Endpoint %u: Best endpoint so far with "
                        "UserTokenPolicy %S", (unsigned)i, utp->policyId);
        } else {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Endpoint %u: Best endpoint so far", (unsigned)i);
        }
    }

    /* No matching endpoint found */
    if(bestEndpointIndex == notFound) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "No suitable endpoint found");
        setConnectStatus(client, UA_STATUSCODE_BADIDENTITYTOKENREJECTED);
        return;
    }

    /* Store the endpoint description in the client. It contains the
     * ApplicationDescription and the UserTokenPolicies. We continue to look up
     * the matching UserTokenPolicy from there. */
    UA_EndpointDescription_clear(&client->endpoint);
    client->endpoint = resp->endpoints[bestEndpointIndex];
    UA_EndpointDescription_init(&resp->endpoints[bestEndpointIndex]);

    if(utp) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u selected with SecurityMode "
                    "%s, SecurityPolicy %S and UserTokenPolicy %S",
                    bestEndpointIndex,
                    securityModeNames[client->endpoint.securityMode],
                    client->endpoint.securityPolicyUri,
                    utp->policyId);
    } else {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Endpoint %u selected with SecurityMode "
                    "%s and SecurityPolicy %S", bestEndpointIndex,
                    securityModeNames[client->endpoint.securityMode],
                    client->endpoint.securityPolicyUri);
    }

    /* A different SecurityMode or SecurityPolicy is defined by the Endpoint.
     * Close the SecureChannel and reconnect. */
    UA_SecurityPolicy *sp = client->channel.securityPolicy;
    if(client->endpoint.securityMode != client->channel.securityMode ||
       !UA_String_equal(&client->endpoint.securityPolicyUri, &sp->policyUri)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "A different SecurityMode or SecurityPolicy is defined "
                    "by the selected Endpoint. Close the SecureChannel "
                    "and reconnect.");
        closeSecureChannel(client);
        return;
    }

    /* We were using a distinct discovery URL and we are switching away from it.
     * Close the SecureChannel to reopen with the EndpointUrl. If an endpoint
     * was selected, then we use the endpointUrl for the HEL message. */
    if(client->discoveryUrl.length > 0 &&
       !UA_String_equal(&client->discoveryUrl, &client->endpoint.endpointUrl)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "The selected endpoint defines an EndpointUrl %S different "
                    "from the Url %S used to connect before calling "
                    "GetEndpoints. Close the SecureChannel and reconnect with "
                    "the new EndpointUrl to ensure the Endpoint is available.",
                    client->discoveryUrl, client->endpoint.endpointUrl);
        closeSecureChannel(client);
        return;
    }

    /* We have selected an endpoint that we can use to open a Session on the
     * current SecureChannel. The remote certificate was validated during
     * processing of the OPN response. But if client->endpoint.serverCertificate
     * is empty we do not compare against the expectation from the endpoint. */

    /* Is the same certificate used for the SecureChannel and the selected
     * endpoint?
     *
     * Both the clientCertificate of this request and the remoteCertificate of
     * the channel may contain a partial or a complete certificate chain. The
     * compareCertificate function will compare the first certificate of each
     * chain. The end certificate shall be located first in the chain according
     * to the OPC UA specification Part 6 (1.04), chapter 6.2.3.*/
    if(client->channel.securityMode != UA_MESSAGESECURITYMODE_NONE) {
        void *cc = client->channel.channelContext;
        UA_StatusCode res = sp->compareCertificate(sp, cc,
                                                   &client->endpoint.serverCertificate);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "The selected endpoint defines a different server certificate "
                        "from then one used by the server for the initial SecureChannel "
                        "(to call GetEndpoints). Close the SecureChannel and reconnect.");
            closeSecureChannel(client);
            return;
        }
    }

    /* Continue with the current SecureChannel */
}

static UA_StatusCode
requestGetEndpoints(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_GetEndpointsRequest request;
    UA_GetEndpointsRequest_init(&request);
    request.endpointUrl = getEndpointUrl(client);

    UA_StatusCode retval =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
                              (UA_ClientAsyncServiceCallback) responseGetEndpoints,
                              &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE], NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "RequestGetEndpoints failed when sending the request with error code %s",
                     UA_StatusCode_name(retval));
        return retval;
    }

    client->endpointsHandshake = true;
    return UA_STATUSCODE_GOOD;
}

static void
responseFindServers(UA_Client *client, void *userdata,
                    UA_UInt32 requestId, void *response) {
    client->findServersHandshake = false;
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Received FindServersResponse");

    /* Error handling. Log the error but continue to connect with the current
     * EndpointURL. */
    UA_FindServersResponse *fsr = (UA_FindServersResponse*)response;
    if(fsr->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "FindServers failed with error code %s. Continue with the "
                       "EndpointURL %S.",
                       UA_StatusCode_name(fsr->responseHeader.serviceResult),
                       client->config.endpointUrl);
        UA_String_clear(&client->discoveryUrl);
        UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
        return;
    }

    /* Check if one of the returned servers matches the EndpointURL already used */
    for(size_t i = 0; i < fsr->serversSize; i++) {
        UA_ApplicationDescription *server = &fsr->servers[i];

        /* Filter by the ApplicationUri if defined */
        if(client->config.applicationUri.length > 0 &&
           !UA_String_equal(&client->config.applicationUri, &server->applicationUri))
            continue;

        for(size_t j = 0; j < server->discoveryUrlsSize; j++) {
            if(UA_String_equal(&client->config.endpointUrl, &server->discoveryUrls[j])) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "The initially defined EndpointURL %S "
                            "is valid for the server", client->config.endpointUrl);
                UA_String_clear(&client->discoveryUrl);
                client->discoveryUrl = server->discoveryUrls[j];
                UA_String_init(&server->discoveryUrls[j]);
                return;
            }
        }
    }

    /* The current EndpointURL is not usable. Pick the first "opc.tcp" DiscoveryUrl of a
     * returned server. */
    for(size_t i = 0; i < fsr->serversSize; i++) {
        UA_ApplicationDescription *server = &fsr->servers[i];
        if(server->applicationType != UA_APPLICATIONTYPE_SERVER &&
            server->applicationType != UA_APPLICATIONTYPE_CLIENTANDSERVER &&
            server->applicationType != UA_APPLICATIONTYPE_DISCOVERYSERVER)
            continue;

        /* Filter by the ApplicationUri if defined */
        if(client->config.applicationUri.length > 0 &&
           !UA_String_equal(&client->config.applicationUri, &server->applicationUri))
            continue;

        for(size_t j = 0; j < server->discoveryUrlsSize; j++) {
            /* Try to parse the DiscoveryUrl. This weeds out http schemas (etc.)
             * and invalid DiscoveryUrls in general. */
            UA_String hostname, path;
            UA_UInt16 port;
            UA_StatusCode res =
                UA_parseEndpointUrl(&server->discoveryUrls[j], &hostname, &port, &path);
            if(res != UA_STATUSCODE_GOOD)
                continue;

            /* Use this DiscoveryUrl in the client */
            UA_String_clear(&client->discoveryUrl);
            client->discoveryUrl = server->discoveryUrls[j];
            UA_String_init(&server->discoveryUrls[j]);

            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Use the EndpointURL %S returned from FindServers and reconnect",
                        client->discoveryUrl);

            /* Close the SecureChannel to build it up new with the correct
             * EndpointURL in the HEL/ACK handshake. In closeSecureChannel the
             * received client->endpoint is reset also. */
            closeSecureChannel(client);
            return;
        }
    }

    /* Could not find a suitable server. Try to continue with the
     * original EndpointURL. */
    UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                   "FindServers did not returned a suitable DiscoveryURL. "
                   "Continue with the EndpointURL %S.", client->config.endpointUrl);
    UA_String_clear(&client->discoveryUrl);
    UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
}

static UA_StatusCode
requestFindServers(UA_Client *client) {
    UA_FindServersRequest request;
    UA_FindServersRequest_init(&request);
    request.requestHeader.timeoutHint = 10000;
    request.endpointUrl = client->config.endpointUrl;
    UA_StatusCode retval =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST],
                              (UA_ClientAsyncServiceCallback) responseFindServers,
                              &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE], NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "FindServers failed when sending the request with error code %s",
                     UA_StatusCode_name(retval));
        return retval;
    }

    client->findServersHandshake = true;
    return UA_STATUSCODE_GOOD;
}

static void
createSessionCallback(UA_Client *client, void *userdata,
                      UA_UInt32 requestId, void *response) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_CreateSessionResponse *csr = (UA_CreateSessionResponse*)response;
    UA_StatusCode res = csr->responseHeader.serviceResult;
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        /* Verify the session response was created with the same certificate as
         * the SecureChannel */
        if(!UA_ByteString_equal(&csr->serverCertificate,
                                &client->channel.remoteCertificate)) {
            res = UA_STATUSCODE_BADCERTIFICATEINVALID;
            goto cleanup;
        }

        /* Verify the client signature */
        res = checkCreateSessionSignature(client, &client->channel, csr);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Copy the SessionId */
    UA_NodeId_clear(&client->sessionId);
    res |= UA_NodeId_copy(&csr->sessionId, &client->sessionId);

    /* Check the (session) nonce length. The session nonce is the application
     * nonce (>= 32 bytes), independent of the SecurityPolicy's SecureChannel
     * nonce length (e.g. the 64-byte ECC ephemeral key). */
    if(csr->serverNonce.length < 32) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Session cannot be created with a nonce "
                     "that is too short");
        res = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto cleanup;
    }

    /* Copy nonce and AuthenticationToken */
    UA_ByteString_clear(&client->serverSessionNonce);
    UA_NodeId_clear(&client->authenticationToken);
    res |= UA_ByteString_copy(&csr->serverNonce, &client->serverSessionNonce);
    res |= UA_NodeId_copy(&csr->authenticationToken, &client->authenticationToken);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Extract the server's ECC ephemeral public key from the CreateSession
     * response */
    extractEphemeralKeyFromAddHeader(client, &csr->responseHeader.additionalHeader);

    /* Activate the new Session */
    client->sessionState = UA_SESSIONSTATE_CREATED;

 cleanup:
    setConnectStatus(client, res);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        client->sessionState = UA_SESSIONSTATE_CLOSED;
}

/* OPC UA Part 6 ECC: request an ephemeral ECDH key from the server by adding an
 * "ECDHPolicyUri" entry (value = the user-token SecurityPolicy URI) to the
 * request's AdditionalHeader. The server returns its ephemeral public key under
 * "ECDHKey" in the response AdditionalHeader, which the client needs to encrypt
 * an ECC UserIdentityToken. For non-ECC user-token policies this is a no-op.
 * The caller must clear the AdditionalHeader after sending. */
static UA_StatusCode
requestServerEphemeralKey(UA_Client *client, UA_RequestHeader *rh) {
    UA_SecurityPolicy *utpSp = client->utpSp;
    if(!UA_SecurityPolicy_isEcc(utpSp))
        return UA_STATUSCODE_GOOD;

    UA_AdditionalParametersType *ap = UA_AdditionalParametersType_new();
    if(!ap)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    ap->parameters = (UA_KeyValuePair*)
        UA_Array_new(1, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(!ap->parameters) {
        UA_AdditionalParametersType_delete(ap);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    ap->parametersSize = 1;
    ap->parameters[0].key = UA_QUALIFIEDNAME_ALLOC(0, "ECDHPolicyUri");
    UA_StatusCode res =
        UA_Variant_setScalarCopy(&ap->parameters[0].value, &utpSp->policyUri,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(res != UA_STATUSCODE_GOOD) {
        UA_AdditionalParametersType_delete(ap);
        return res;
    }
    UA_ExtensionObject_setValue(&rh->additionalHeader, ap,
                                &UA_TYPES[UA_TYPES_ADDITIONALPARAMETERSTYPE]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
createSessionAsync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Select the UserTokenPolicy based on the client configuration and the
     * endpoint information. Also instantiates the UserTokenPolicy if not
     * already there. */
    const UA_UserTokenPolicy *utp = NULL;
    UA_StatusCode res = initUserTokenPolicy(client, &utp, "CreateSession");
    if(res != UA_STATUSCODE_GOOD)
        return res;
    (void)utp;

    /* Create the CreateSession ClientNonce: a 32-byte random nonce when the
     * SecureChannel is secured. For ECC SecurityPolicies the ClientNonce is
     * NOT the session ephemeral key — the ephemeral keys are exchanged
     * separately (the server's arrives in the response AdditionalHeader; the
     * client's, when needed for UserIdentityToken encryption, is carried in
     * the EccEncryptedSecret). Sending the ephemeral key as the nonce is
     * rejected by conformant servers with BadNonceInvalid. */
    UA_SecurityPolicy *sp = client->channel.securityPolicy;
    if(sp && client->channel.securityMode != UA_MESSAGESECURITYMODE_NONE) {
        size_t nonceLength = 32;
        if(client->clientSessionNonce.length != nonceLength) {
            UA_ByteString_clear(&client->clientSessionNonce);
            res = UA_ByteString_allocBuffer(&client->clientSessionNonce, nonceLength);
            if(res != UA_STATUSCODE_GOOD)
                return res;
        }
        /* Ensure data[0] is not the 'e' of the "eph" ECC ephemeral-key
         * trigger, so generateNonce produces plain random data. */
        client->clientSessionNonce.data[0] = 0;
        res = sp->generateNonce(sp, client->channel.channelContext,
                                &client->clientSessionNonce);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "CreateSession could not create the client nonce");
            return res;
        }
    }

    /* Prepare the request */
    UA_CreateSessionRequest request;
    UA_CreateSessionRequest_init(&request);
    request.clientNonce = client->clientSessionNonce;
    request.requestedSessionTimeout = client->config.requestedSessionTimeout;
    request.maxResponseMessageSize = UA_INT32_MAX;
    request.endpointUrl = client->endpoint.endpointUrl;
    request.clientDescription = client->config.clientDescription;
    request.sessionName = client->config.sessionName;

    /* Send the certificate that is used for the UserIdentiyToken as the
     * ApplicationCertificate. (sp == client->channel.securityPolicy; guarded
     * so static analysis sees it cannot be a NULL dereference.) */
    if(sp)
        request.clientCertificate = sp->localCertificate;

    /* For ECC policies, request the server's ephemeral ECDH key (needed to
     * encrypt the UserIdentityToken in ActivateSession). */
    res = requestServerEphemeralKey(client, &request.requestHeader);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Send the request */
    res = __Client_AsyncService(client, &request,
                                &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
                                (UA_ClientAsyncServiceCallback)createSessionCallback,
                                &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE], NULL, NULL);

    /* The request is encoded+sent synchronously; release the AdditionalHeader. */
    UA_ExtensionObject_clear(&request.requestHeader.additionalHeader);

    if(res == UA_STATUSCODE_GOOD)
        client->sessionState = UA_SESSIONSTATE_CREATE_REQUESTED;
    else
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "CreateSession failed when sending the request with "
                     "error code %s", UA_StatusCode_name(res));

    return res;
}

static UA_StatusCode
initSecurityPolicy(UA_Client *client) {
    /* Find the SecurityPolicy. Use #None if the endpoint is not (yet)
     * configured. */
    UA_String secPolicyUri = client->endpoint.securityPolicyUri;
    if(secPolicyUri.length == 0)
        secPolicyUri = UA_SECURITY_POLICY_NONE_URI;
    UA_SecurityPolicy *sp = getSecurityPolicy(client, secPolicyUri);

    /* Unknown SecurityPolicy */
    if(!sp) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "SecurityPolicy %S not available", secPolicyUri);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Already initialized -- check we are using the same SecurityPolicy */
    if(client->channel.securityPolicy)
        return (client->channel.securityPolicy == sp) ?
            UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;

    /* Verify the remote server certificate */
    UA_StatusCode res;
    if(client->endpoint.serverCertificate.length > 0) {
        res = client->config.certificateVerification.
            verifyCertificate(&client->config.certificateVerification,
                              &client->endpoint.serverCertificate);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Cannot validate the server certificate "
                         "defined for the selected endpoint");
            return res;
        }
    }

    /* If the sender provides a chain of certificates then we shall extract the
     * ApplicationInstanceCertificate and ignore the extra bytes. See also: OPC
     * UA Part 6, V1.04, 6.7.2.3 Security Header, Table 42 - Asymmetric
     * algorithm Security header */
    UA_ByteString appInstCert =
        getLeafCertificate(client->endpoint.serverCertificate);

    /* Instantiate the SecurityPolicy context with the remote certificate */
    res = UA_SecureChannel_setSecurityPolicy(&client->channel, sp, &appInstCert);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Cannot instantiate the SecurityPolicy %S "
                     "with the supplied server certificate", sp->policyUri);
        return res;
    }

    /* Set the SecurityMode. Replace INVALID with NONE as a workaround for
     * misconfigured endpoints. */
    UA_MessageSecurityMode securityMode = client->endpoint.securityMode;
    if(securityMode == UA_MESSAGESECURITYMODE_INVALID)
        securityMode = UA_MESSAGESECURITYMODE_NONE;
    res = UA_SecureChannel_setSecurityMode(&client->channel, securityMode);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Client configuration uses mismatching "
                     "MessageSecurityMode==%u for SecurityPolicy %S",
                     securityMode, sp->policyUri);
    }
    return res;
}

static void
connectActivity(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);
    UA_LOG_TRACE(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Client connect iterate");

    /* Could not connect with an error that canot be recovered from */
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    /* Already connected */
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
        return;

    /* Switch on the SecureChannel state */
    switch(client->channel.state) {
        /* Nothing to do if the connection has not opened fully */
    case UA_SECURECHANNELSTATE_CONNECTING:
    case UA_SECURECHANNELSTATE_REVERSE_CONNECTED:
    case UA_SECURECHANNELSTATE_CLOSING:
    case UA_SECURECHANNELSTATE_HEL_SENT:
    case UA_SECURECHANNELSTATE_OPN_SENT:
        return;

        /* Send HEL */
    case UA_SECURECHANNELSTATE_CONNECTED:
        setConnectStatus(client, sendHELMessage(client));
        return;

        /* ACK receieved. Send OPN. */
    case UA_SECURECHANNELSTATE_ACK_RECEIVED:
        setConnectStatus(client, sendOPNAsync(client, false)); /* Send OPN */
        return;

        /* The channel is open -> continue with the Session handling */
    case UA_SECURECHANNELSTATE_OPEN:
        break;

        /* The connection is closed. Reset the SecureChannel and open a new TCP
         * connection */
    case UA_SECURECHANNELSTATE_CLOSED:
        if(client->config.noReconnect)
            setConnectStatus(client, UA_STATUSCODE_BADNOTCONNECTED);
        else
            initConnect(client); /* Sets the connectStatus internally */
        return;

        /* These states should never occur for the client */
    default:
        setConnectStatus(client, UA_STATUSCODE_BADINTERNALERROR);
        return;
    }

    /* <-- The SecureChannel is open --> */

    /* Ongoing handshake -> Waiting for a response */
    if(client->endpointsHandshake || client->findServersHandshake ||
       client->namespacesHandshake)
        return;

    /* Call FindServers to see if we should reconnect with another EndpointUrl.
     * This needs to be done before GetEndpoints, as the set of returned
     * endpoints may depend on the EndpointUrl used during the initial HEL/ACK
     * handshake. */
    if(client->discoveryUrl.length == 0) {
        setConnectStatus(client, requestFindServers(client));
        return;
    }

    /* GetEndpoints to identify the remote side and/or reset the SecureChannel
     * with encryption */
    if(endpointUnconfigured(&client->endpoint)) {
        setConnectStatus(client, requestGetEndpoints(client));
        return;
    }

    /* Have the final SecureChannel but no session */
    if(client->config.noSession)
        return;

    /* Create and Activate the Session */
    switch(client->sessionState) {
        /* Send a CreateSessionRequest */
    case UA_SESSIONSTATE_CLOSED:
        setConnectStatus(client, createSessionAsync(client));
        return;

        /* Activate the Session */
    case UA_SESSIONSTATE_CREATED:
        setConnectStatus(client, activateSessionAsync(client));
        return;

    case UA_SESSIONSTATE_CREATE_REQUESTED:
    case UA_SESSIONSTATE_ACTIVATE_REQUESTED:
    case UA_SESSIONSTATE_ACTIVATED:
    case UA_SESSIONSTATE_CLOSING:
        return; /* Nothing to do */

        /* These states should never occur for the client */
    default:
        setConnectStatus(client, UA_STATUSCODE_BADINTERNALERROR);
        break;
    }
}

/* Verify the OPN response. Note that the client knows the remote server
 * certificate before opening the SecureChannel (from the EndpointDescription).
 *
 * The server certificate is used to initialize the SecureChannel/SecurityPolicy
 * before connecting in initSecurityPolicy. The certificate from the endpoint is
 * checked to be the same used in the AsymHeader. */
static UA_StatusCode
verifyClientSecureChannelHeader(void *application, UA_SecureChannel *channel,
                                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
    UA_Client *client = (UA_Client*)application;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_assert(sp != NULL);

    /* Check the SecurityPolicyUri if it is defined. If the SecurityMode is not
     * None, then the SecurityPolicyUri must be defined. For None we allow an
     * empty SecurityPolicyUri to support all (historical) server behaviors. */
    if((asymHeader->securityPolicyUri.length > 0 ||
        channel->securityMode != UA_MESSAGESECURITYMODE_NONE) &&
       !UA_String_equal(&sp->policyUri, &asymHeader->securityPolicyUri)) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "The server uses a different SecurityPolicy than "
                     "the SecureChannel/Endpoint configured in the client");
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    /* In initSecurityPolicy we already verified
     * client->endpoint.serverCertificate and loaded it into the channel context
     * of the SecurityPolicy.
     *
     * If the securityPolicyUri is None (== SecurityMode is None), the server
     * shall ignore the ApplicationInstanceCertificate. Otherwise compare that
     * the certificate in OPN is the same as in the endpoint.
     *
     * Both the clientCertificate of this request and of the endpoint may
     * contain a partial or a complete certificate chain. The compareCertificate
     * function will compare the first certificate of each chain. The end
     * certificate shall be located first in the chain according to the OPC UA
     * specification Part 6 (1.04), chapter 6.2.3.*/
    UA_StatusCode res;
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE) {
        void *cc = channel->channelContext;
        res = sp->compareCertificate(sp, cc, &asymHeader->senderCertificate);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "The server certificate in the OPN message is "
                         "different from the EndpointDescription");
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        }
    }

    /* Verify the certificate the server assumes on our end */
    res = sp->compareCertThumbprint(sp, &asymHeader->receiverCertificateThumbprint);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "The client certificate thumprint in the OPN response "
                     "is incorrect");
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

/* The local ApplicationUri has to match the certificates of the
 * SecurityPolicies */
static void
verifyClientApplicationUri(const UA_Client *client) {
#if UA_LOGLEVEL <= 400
    const UA_ClientConfig *cc = &client->config;
    for(size_t i = 0; i < cc->securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &cc->securityPolicies[i];
        if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE &&
           !sp->localCertificate.data)
            continue;
        UA_StatusCode retval =
            UA_CertificateUtils_verifyApplicationUri(&sp->localCertificate,
                                &cc->clientDescription.applicationUri);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(cc->logging, UA_LOGCATEGORY_CLIENT,
                           "The ApplicationUri %S in the client's ApplicationDescription "
                           "does not match the URI specified in the certificate "
                           "for the SecurityPolicy %S",
                           cc->clientDescription.applicationUri, sp->policyUri);
        }
    }
#endif
}

static void
delayedNetworkCallback(void *application, void *context);

static void
__Client_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                         void *application, void **connectionContext,
                         UA_ConnectionState state, const UA_KeyValueMap *params,
                         UA_ByteString msg) {
    /* Take the client lock */
    UA_Client *client = (UA_Client*)application;
    lockClient(client);

    UA_LOG_TRACE(client->config.logging, UA_LOGCATEGORY_CLIENT, "Client network callback");

    /* A new connection with no context pointer attached */
    if(!*connectionContext) {
        /* Inconsistent SecureChannel state. Has to be fresh for a new
         * connection. */
        if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED &&
           client->channel.state != UA_SECURECHANNELSTATE_REVERSE_LISTENING) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Cannot open a connection, the SecureChannel is already used");
            setConnectStatus(client, UA_STATUSCODE_BADINTERNALERROR);
            notifyClientState(client);
            unlockClient(client);
            return;
        }

        /* Initialize the client connection and attach to the EventLoop connection */
        client->channel.connectionManager = cm;
        client->channel.connectionId = connectionId;
        *connectionContext = &client->channel;
    }

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel,
                            "SecureChannel closed");

        /* Set to closing (could be done already in UA_SecureChannel_shutdown).
         * This impacts the handling of cancelled requests below. */
        UA_SecureChannelState oldState = client->channel.state;
        client->channel.state = UA_SECURECHANNELSTATE_CLOSING;

        /* Set the Session to CREATED if it was ACTIVATED */
        if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
            client->sessionState = UA_SESSIONSTATE_CREATED;

        /* Delete outstanding async services - the RequestId is no longer valid. Do
         * this after setting the Session state. Otherwise we send out new Publish
         * Requests immediately. */
        __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSECURECHANNELCLOSED);

        /* Clean up the channel and set the status to CLOSED */
        UA_SecureChannel_clear(&client->channel);

        /* The connection closed before it actually opened. Since we are
         * connecting asynchronously, this happens when the TCP connection
         * fails. Try to fall back on the initial EndpointUrl. */
        if(oldState == UA_SECURECHANNELSTATE_CONNECTING &&
           client->connectStatus == UA_STATUSCODE_GOOD)
            setConnectStatus(client, fallbackEndpointUrl(client));

        /* Try to reconnect. Duplicate the code instead of continue_connect to
         * pacify compiler warnings. */
        /* goto continue_connect; */
        if(!isFullyConnected(client))
            connectActivity(client);
        notifyClientState(client);
        unlockClient(client);
        return;
    }

    /* Update the SecureChannel state */
    if(UA_LIKELY(state == UA_CONNECTIONSTATE_ESTABLISHED)) {
        /* The connection is now open on the TCP level. Set the SecureChannel
         * state to reflect this. Otherwise later consistency checks for the
         * received messages fail. */
        if(client->channel.state < UA_SECURECHANNELSTATE_CONNECTED)
            client->channel.state = UA_SECURECHANNELSTATE_CONNECTED;
    } else /* state == UA_CONNECTIONSTATE_OPENING */ {
        /* The connection was opened on our end only. Waiting for the TCP handshake
         * to complete. */
        client->channel.state = UA_SECURECHANNELSTATE_CONNECTING;
    }

    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);

    /* Received a message. Process the message with the SecureChannel. */
    UA_StatusCode res = UA_SecureChannel_loadBuffer(&client->channel, msg);
    while(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
        UA_MessageType messageType;
        UA_UInt32 requestId = 0;
        UA_ByteString payload = UA_BYTESTRING_NULL;
        UA_Boolean copied = false;
        res = UA_SecureChannel_getCompleteMessage(&client->channel, &messageType, &requestId,
                                                  &payload, &copied, nowMonotonic);
        if(res != UA_STATUSCODE_GOOD || payload.length == 0)
            break;
        res = processServiceResponse(client, &client->channel,
                                     messageType, requestId, &payload);
        if(copied)
            UA_ByteString_clear(&payload);

        /* Abort after synchronous processing of a message.
         * Add a delayed callback to process the remaining buffer ASAP. */
        if(res == UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY) {
            if(client->channel.unprocessed.length > client->channel.unprocessedOffset &&
               client->channel.unprocessedDelayed.callback == NULL) {
                client->channel.unprocessedDelayed.callback = delayedNetworkCallback;
                client->channel.unprocessedDelayed.application = client;
                client->channel.unprocessedDelayed.context = &client->channel;
                el->addDelayedCallback(el, &client->channel.unprocessedDelayed);
            }
            res = UA_STATUSCODE_GOOD;
            break;
        }
    }
    res |= UA_SecureChannel_persistBuffer(&client->channel);

    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Processing the message returned the error code %s",
                     UA_StatusCode_name(res));

        /* If processing the buffer fails before the SecureChannel has opened,
         * then the client cannot recover. Set the connectStatus to reflect
         * this. The application is notified when the socket has closed. */
        if(client->channel.state != UA_SECURECHANNELSTATE_OPEN)
            setConnectStatus(client, res);

        /* Close the SecureChannel, but don't notify the client right away.
         * Return immediately. notifyClientState will be called in the next
         * callback from the ConnectionManager when the connection closes with a
         * StatusCode.
         *
         * If the connectStatus is still good (the SecureChannel was fully
         * opened before), then a reconnect is attempted. */
        closeSecureChannel(client);
        unlockClient(client);
        return;
    }

    /* continue_connect: */
    /* Trigger the next action from our end to fully open up the connection */
    if(!isFullyConnected(client))
        connectActivity(client);
    notifyClientState(client);
    unlockClient(client);
}

static void
delayedNetworkCallback(void *application, void *context) {
    UA_Client *client = (UA_Client*)application;
    client->channel.unprocessedDelayed.callback = NULL;
    if(client->channel.state >= UA_SECURECHANNELSTATE_CONNECTING)
        __Client_networkCallback(client->channel.connectionManager,
                                 client->channel.connectionId,
                                 client, &context,
                                 UA_CONNECTIONSTATE_ESTABLISHED,
                                 &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
}

/* Initialize a TCP connection. Writes the result to client->connectStatus. */
static void
initConnect(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);
    if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Client connection already initiated");
        return;
    }

    UA_StatusCode res;

    /* An exact endpoint was configured. Use it. */
    if(!endpointUnconfigured(&client->config.endpoint)) {
        UA_EndpointDescription_clear(&client->endpoint);
        res = UA_EndpointDescription_copy(&client->config.endpoint, &client->endpoint);
        if(res != UA_STATUSCODE_GOOD) {
            setConnectStatus(client, res);
            return;
        }
    }

    /* Start the EventLoop if not already started */
    setConnectStatus(client, __UA_Client_startup(client));
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    /* Consistency check the client's own ApplicationUri.
     * Problems are only logged. */
    verifyClientApplicationUri(client);

    /* Initialize the SecureChannel */
    UA_SecureChannel_clear(&client->channel);
    client->channel.config = client->config.localConnectionConfig;
    client->channel.processOPNHeader = verifyClientSecureChannelHeader;
    client->channel.processOPNHeaderApplication = client;

    /* Initialize the SecurityPolicy */
    setConnectStatus(client, initSecurityPolicy(client));
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    /* Extract hostname and port from the URL */
    UA_String hostname = UA_STRING_NULL;
    UA_String path = UA_STRING_NULL;
    UA_UInt16 port = 4840;

    res = UA_parseEndpointUrl(&client->config.endpointUrl, &hostname, &port, &path);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
                       "Endpoint URL is invalid: %S", client->config.endpointUrl);
        setConnectStatus(client, res);
        return;
    }

    /* Initialize the TCP connection */
    UA_String tcpString = UA_STRING("tcp");
    for(UA_EventSource *es = client->config.eventLoop->eventSources;
        es != NULL; es = es->next) {
        /* Is this a usable connection manager? */
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(!UA_String_equal(&tcpString, &cm->protocol))
            continue;

        /* Set up the parameters */
        UA_KeyValuePair params[3];
        params[0].key = UA_QUALIFIEDNAME(0, "port");
        UA_Variant_setScalar(&params[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
        params[1].key = UA_QUALIFIEDNAME(0, "address");
        UA_Variant_setScalar(&params[1].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
        params[2].key = UA_QUALIFIEDNAME(0, "reuse");
        UA_Variant_setScalar(&params[2].value, &client->config.tcpReuseAddr,
                             &UA_TYPES[UA_TYPES_BOOLEAN]);

        UA_KeyValueMap paramMap;
        paramMap.map = params;
        paramMap.mapSize = 3;

        /* Open the client TCP connection */
        res = cm->openConnection(cm, &paramMap, client, NULL, __Client_networkCallback);
        if(res == UA_STATUSCODE_GOOD)
            break;
    }

    /* The channel has not opened */
    if(client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
        res = UA_STATUSCODE_BADINTERNALERROR;

    /* Opening the TCP connection failed */
    if(res != UA_STATUSCODE_GOOD || client->connectStatus != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Could not open a TCP connection to %S",
                       client->config.endpointUrl);
        setConnectStatus(client, UA_STATUSCODE_BADCONNECTIONCLOSED);
    }
}

void
connectSync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Initialize the connection */
    initConnect(client);
    notifyClientState(client);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    /* EventLoop is started. Otherwise initConnect would have failed. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_assert(el);

    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime maxDate = now + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC);

    /* Run the EventLoop until connected, connect fail or timeout. Continue
     * to iterate when the channel is in CLOSING state so that the pending
     * close callback is processed and the channel fully transitions to CLOSED
     * before returning to the caller. */
    while((client->connectStatus == UA_STATUSCODE_GOOD && !isFullyConnected(client)) ||
          client->channel.state == UA_SECURECHANNELSTATE_CLOSING) {
        /* Timeout -> abort */
        now = el->dateTime_nowMonotonic(el);
        if(maxDate < now) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "The connection has timed out before it could be fully opened");
            setConnectStatus(client, UA_STATUSCODE_BADTIMEOUT);
            /* Continue to run. The loop continues while the channel is
             * CLOSING so the close callback is processed. */
        }

        /* Drop into the EventLoop */
        UA_StatusCode res = el->run(el, (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC));
        if(res != UA_STATUSCODE_GOOD)
            setConnectStatus(client, res);
    }
}

UA_StatusCode
connectInternal(UA_Client *client, UA_Boolean async) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Reset the connectStatus. This should be the only place where we can
     * recover from a bad connectStatus. */
    client->connectStatus = UA_STATUSCODE_GOOD;

    if(async)
        initConnect(client);
    else
        connectSync(client);
    notifyClientState(client);
    return client->connectStatus;
}

UA_StatusCode
connectSecureChannel(UA_Client *client, const char *endpointUrl) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_ClientConfig *cc = UA_Client_getConfig(client);
    cc->noSession = true;
    UA_String_clear(&cc->endpointUrl);
    cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
    return connectInternal(client, false);
}

UA_StatusCode
__UA_Client_connect(UA_Client *client, UA_Boolean async, const char *endpointUrl) {
    lockClient(client);

    UA_ClientConfig *cc = UA_Client_getConfig(client);
    if(endpointUrl) {
        UA_String_clear(&cc->endpointUrl);
        cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
    }

    connectInternal(client, async);

    unlockClient(client);
    return client->connectStatus;
}

static UA_StatusCode
activateSessionSync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* EventLoop is started. Otherwise activateSessionAsync would have failed. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_assert(el);

    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime maxDate = now + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC);

    /* Try to activate */
    UA_StatusCode res = activateSessionAsync(client);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Continue iterating while the session is being activated or the
     * channel is draining (CLOSING) after a timeout. */
    while((client->sessionState != UA_SESSIONSTATE_ACTIVATED &&
          client->connectStatus == UA_STATUSCODE_GOOD) ||
          client->channel.state == UA_SECURECHANNELSTATE_CLOSING) {
        /* Timeout -> abort */
        now = el->dateTime_nowMonotonic(el);
        if(maxDate < now) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "The connection has timed out before it could be fully opened");
            setConnectStatus(client, UA_STATUSCODE_BADTIMEOUT);
            /* Continue to run. The loop continues while the channel is
             * CLOSING so the close callback is processed. */
        }

        /* Drop into the EventLoop */
        res = el->run(el, (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC));
        if(res != UA_STATUSCODE_GOOD)
            setConnectStatus(client, res);
    }

    return client->connectStatus;
}

UA_StatusCode
UA_Client_activateCurrentSession(UA_Client *client) {
    lockClient(client);
    UA_StatusCode res = activateSessionSync(client);
    notifyClientState(client);
    unlockClient(client);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

UA_StatusCode
UA_Client_activateCurrentSessionAsync(UA_Client *client) {
    lockClient(client);
    UA_StatusCode res = activateSessionAsync(client);
    notifyClientState(client);
    unlockClient(client);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

UA_StatusCode
UA_Client_getSessionAuthenticationToken(UA_Client *client,
                                        UA_NodeId *authenticationToken,
                                        UA_ByteString *serverNonce) {
    lockClient(client);
    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "There is no current session");
        unlockClient(client);
        return UA_STATUSCODE_BADSESSIONCLOSED;
    }

    UA_StatusCode res =
        UA_NodeId_copy(&client->authenticationToken, authenticationToken);
    res |= UA_ByteString_copy(&client->serverSessionNonce, serverNonce);
    unlockClient(client);
    return res;
}

static UA_StatusCode
switchSession(UA_Client *client,
              const UA_NodeId authenticationToken,
              const UA_ByteString serverNonce) {
    /* Check that there is no pending session in the client */
    if(client->sessionState != UA_SESSIONSTATE_CLOSED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Cannot activate a session with a different AuthenticationToken "
                     "when the client already has a Session.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Replace token and nonce */
    UA_NodeId_clear(&client->authenticationToken);
    UA_ByteString_clear(&client->serverSessionNonce);
    UA_StatusCode res = UA_NodeId_copy(&authenticationToken,
                                       &client->authenticationToken);
    res |= UA_ByteString_copy(&serverNonce, &client->serverSessionNonce);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Notify that we have now a created session */
    client->sessionState = UA_SESSIONSTATE_CREATED;
    notifyClientState(client);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_activateSession(UA_Client *client,
                          const UA_NodeId authenticationToken,
                          const UA_ByteString serverNonce) {
    lockClient(client);
    UA_StatusCode res = switchSession(client, authenticationToken, serverNonce);
    if(res != UA_STATUSCODE_GOOD) {
        unlockClient(client);
        return res;
    }
    res = activateSessionSync(client);
    notifyClientState(client);
    unlockClient(client);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

UA_StatusCode
UA_Client_activateSessionAsync(UA_Client *client,
                               const UA_NodeId authenticationToken,
                               const UA_ByteString serverNonce) {
    lockClient(client);
    UA_StatusCode res = switchSession(client, authenticationToken, serverNonce);
    if(res != UA_STATUSCODE_GOOD) {
        unlockClient(client);
        return res;
    }
    res = activateSessionAsync(client);
    notifyClientState(client);
    unlockClient(client);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

static void
disconnectListenSockets(UA_Client *client) {
    UA_ConnectionManager *cm = client->reverseConnectionCM;
    for(size_t i = 0; i < 16; i++) {
        if(client->reverseConnectionIds[i] != 0)
            cm->closeConnection(cm, client->reverseConnectionIds[i]);
    }
}

/* ConnectionContext meaning:
 * - NULL: New listen connection
 * - &client->channel: Established active socket to a server
 * - &client->reverseConnectionIds[*] == connectionId: Established listen socket
 * - &client->reverseConnectionIds[*] != connectionId: New active socket */
static void
__Client_reverseConnectCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                                void *application, void **connectionContext,
                                UA_ConnectionState state, const UA_KeyValueMap *params,
                                UA_ByteString msg) {
    UA_Client *client = (UA_Client*)application;
    lockClient(client);

    if(!*connectionContext) {
        /* Store the new listen connection */
        size_t i = 0;
        for(; i < 16; i++) {
            if(client->reverseConnectionIds[i] == 0) {
                client->reverseConnectionIds[i] = connectionId;
                client->reverseConnectionCM = cm;
                *connectionContext = &client->reverseConnectionIds[i];
                if(client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
                    client->channel.state = UA_SECURECHANNELSTATE_REVERSE_LISTENING;
                break;
            }
        }
        /* All slots are full, close */
        if(i == 16) {
            cm->closeConnection(cm, connectionId);
            unlockClient(client);
            return;
        }
    } else if(*connectionContext == &client->channel ||
              *(uintptr_t*)*connectionContext != connectionId) {
        /* Active socket */

        /* New active socket */
        if(*connectionContext != &client->channel) {
            /* The client already has an active connection */
            if(client->channel.connectionId) {
                cm->closeConnection(cm, connectionId);
                unlockClient(client);
                return;
            }

            /* Set the connection the SecureChannel */
            client->channel.connectionId = connectionId;
            client->channel.connectionManager = cm;
            *connectionContext = &client->channel;

            /* Don't keep the listen sockets when an active connection is open */
            disconnectListenSockets(client);

            /* Set the channel state. The notification callback is called within
             * __Client_reverseConnectCallback. */
            if(client->channel.state == UA_SECURECHANNELSTATE_REVERSE_LISTENING)
                client->channel.state = UA_SECURECHANNELSTATE_REVERSE_CONNECTED;
        }

        /* Handle the active connection in the normal network callback */
        unlockClient(client);
        __Client_networkCallback(cm, connectionId, application,
                                 connectionContext, state, params, msg);
        return;
    }

    /* Close the listen socket. Was this the last one? */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        UA_Byte count = 0;
        for(size_t i = 0; i < 16; i++) {
            if(client->reverseConnectionIds[i] == connectionId)
                client->reverseConnectionIds[i] = 0;
            if(client->reverseConnectionIds[i] != 0)
                count++;
        }
        /* The last connection was closed */
        if(count == 0 && client->channel.connectionId == 0)
            client->channel.state = UA_SECURECHANNELSTATE_CLOSED;
    }

    notifyClientState(client);
    unlockClient(client);
}

UA_StatusCode
UA_Client_startListeningForReverseConnect(UA_Client *client,
                                          const UA_String *listenHostnames,
                                          size_t listenHostnamesLength,
                                          UA_UInt16 port) {
    lockClient(client);

    if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Unable to listen for reverse connect while the client "
                       "is connected or already listening");
        unlockClient(client);
        return UA_STATUSCODE_BADINVALIDSTATE;
    }

    const UA_String tcpString = UA_STRING_STATIC("tcp");
    UA_StatusCode res = UA_STATUSCODE_BADINTERNALERROR;

    client->connectStatus = UA_STATUSCODE_GOOD;
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;

    UA_SecureChannel_init(&client->channel);
    client->channel.config = client->config.localConnectionConfig;
    client->channel.processOPNHeader = verifyClientSecureChannelHeader;
    client->channel.processOPNHeaderApplication = client;
    client->channel.connectionId = 0;

    setConnectStatus(client, initSecurityPolicy(client));
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return client->connectStatus;

    UA_EventLoop *el = client->config.eventLoop;
    if(!el) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "No EventLoop configured");
        unlockClient(client);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(el->state != UA_EVENTLOOPSTATE_STARTED) {
        res = el->start(el);
        UA_CHECK_STATUS(res, unlockClient(client); return res);
    }

    UA_ConnectionManager *cm = NULL;
    for(UA_EventSource *es = el->eventSources; es != NULL; es = es->next) {
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        cm = (UA_ConnectionManager*)es;
        if(UA_String_equal(&tcpString, &cm->protocol))
            break;
        cm = NULL;
    }

    if(!cm) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Could not find a TCP connection manager, unable to "
                       "listen for reverse connect");
        unlockClient(client);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    client->channel.connectionManager = cm;

    UA_KeyValuePair params[4];
    bool booleanTrue = true;
    params[0].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&params[0].value, &port,
                         &UA_TYPES[UA_TYPES_UINT16]);
    params[1].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setArray(&params[1].value, (void *)(uintptr_t)listenHostnames,
            listenHostnamesLength, &UA_TYPES[UA_TYPES_STRING]);
    params[2].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&params[2].value, &booleanTrue,
                         &UA_TYPES[UA_TYPES_BOOLEAN]);
    params[3].key = UA_QUALIFIEDNAME(0, "reuse");
    UA_Variant_setScalar(&params[3].value, &client->config.tcpReuseAddr,
                         &UA_TYPES[UA_TYPES_BOOLEAN]);

    UA_KeyValueMap paramMap;
    paramMap.map = params;
    paramMap.mapSize = 4;

    res = cm->openConnection(cm, &paramMap, client, NULL,
                             __Client_reverseConnectCallback);

    /* Opening the TCP connection failed */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Failed to open a listening TCP socket for "
                       "reverse connect");
        res = UA_STATUSCODE_BADCONNECTIONCLOSED;
    }

    unlockClient(client);
    return res;
}

/************************/
/* Close the Connection */
/************************/

void
closeSecureChannel(UA_Client *client) {
    /* If we close SecureChannel when the Session is still active, set to
     * created. Otherwise the Session would remain active until the connection
     * callback is called for the closing connection. */
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
        client->sessionState = UA_SESSIONSTATE_CREATED;

    /* Prevent recursion */
    if(client->channel.state == UA_SECURECHANNELSTATE_CLOSING ||
       client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
        return;

    UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                         "Closing the channel");

    disconnectListenSockets(client);

    /* Send CLO if the SecureChannel is open */
    if(client->channel.state == UA_SECURECHANNELSTATE_OPEN) {
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                             "Sending the CLO message");

        UA_EventLoop *el = client->config.eventLoop;

        /* Manually set up the header (otherwise done in sendRequest) */
        UA_CloseSecureChannelRequest request;
        UA_CloseSecureChannelRequest_init(&request);
        request.requestHeader.requestHandle = ++client->requestHandle;
        request.requestHeader.timestamp = el->dateTime_now(el);
        request.requestHeader.timeoutHint = client->config.timeout;
        request.requestHeader.authenticationToken = client->authenticationToken;
        UA_SecureChannel_sendCLO(&client->channel, ++client->requestId, &request);
    }

    /* The connection is eventually closed in the next callback from the
     * ConnectionManager with the appropriate status code. Don't set the
     * connection closed right away! */
    UA_SecureChannel_shutdown(&client->channel, UA_SHUTDOWNREASON_CLOSE);
}

static void
sendCloseSession(UA_Client *client) {
    UA_CloseSessionRequest request;
    UA_CloseSessionRequest_init(&request);
    request.deleteSubscriptions = true;
    UA_CloseSessionResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
                        &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
    UA_CloseSessionRequest_clear(&request);
    UA_CloseSessionResponse_clear(&response);

    /* Set after sending the message to prevent immediate reoping during the
     * service call */
    client->sessionState = UA_SESSIONSTATE_CLOSING;
}

void
cleanupSession(UA_Client *client) {
    UA_NodeId_clear(&client->sessionId);
    UA_NodeId_clear(&client->authenticationToken);
    client->requestHandle = 0;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* We need to clean up the subscriptions */
    __Client_Subscriptions_clear(client);
#endif

    /* Delete outstanding async services */
    __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSESSIONCLOSED);

#ifdef UA_ENABLE_SUBSCRIPTIONS
    client->currentlyOutStandingPublishRequests = 0;
#endif

    client->sessionState = UA_SESSIONSTATE_CLOSED;

    /* Clean the latest server's ephemeral public key */
    UA_ByteString_clear(&client->serverEphemeralPubKey);
    if(client->utpSp && client->utpSpContext) {
        client->utpSp->deleteChannelContext(client->utpSp, client->utpSpContext);
        client->utpSp = NULL;
        client->utpSpContext = NULL;
    }
}

static void
disconnectSecureChannel(UA_Client *client, UA_Boolean sync) {
    /* Clean the DiscoveryUrl and endpoint description when the connection is
     * explicitly closed */
    UA_String_clear(&client->discoveryUrl);
    UA_EndpointDescription_clear(&client->endpoint);

    /* Close the SecureChannel */
    closeSecureChannel(client);

    /* Manually set the status to closed to prevent an automatic reconnection.
     * Notify the client at the end. */
    if(client->connectStatus == UA_STATUSCODE_GOOD)
        client->connectStatus = UA_STATUSCODE_BADCONNECTIONCLOSED;

    /* In the synchronous case, loop until the client has actually closed. */
    UA_EventLoop *el = client->config.eventLoop;
    if(sync && el &&
       el->state != UA_EVENTLOOPSTATE_FRESH &&
       el->state != UA_EVENTLOOPSTATE_STOPPED) {
        while(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
            UA_StatusCode runStatus = el->run(el, 100);
            if(runStatus != UA_STATUSCODE_GOOD) {
                UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                             "EventLoop run returned %s during synchronous disconnect, "
                             "stopping wait loop", UA_StatusCode_name(runStatus));
                break;
            }
        }
    }

    notifyClientState(client);
}

UA_StatusCode
UA_Client_disconnectSecureChannel(UA_Client *client) {
    lockClient(client);
    disconnectSecureChannel(client, true);
    unlockClient(client);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_disconnectSecureChannelAsync(UA_Client *client) {
    lockClient(client);
    disconnectSecureChannel(client, false);
    unlockClient(client);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_disconnect(UA_Client *client) {
    lockClient(client);
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
        sendCloseSession(client);
    cleanupSession(client);
    disconnectSecureChannel(client, true);
    unlockClient(client);
    return UA_STATUSCODE_GOOD;
}

static void
closeSessionCallback(UA_Client *client, void *userdata,
                     UA_UInt32 requestId, void *response) {
    lockClient(client);
    cleanupSession(client);
    disconnectSecureChannel(client, false);
    notifyClientState(client);
    unlockClient(client);
}

UA_StatusCode
UA_Client_disconnectAsync(UA_Client *client) {
    lockClient(client);

    if(client->sessionState == UA_SESSIONSTATE_CLOSED ||
       client->sessionState == UA_SESSIONSTATE_CLOSING) {
        disconnectSecureChannel(client, false);
        notifyClientState(client);
        unlockClient(client);
        return UA_STATUSCODE_GOOD;
    }

    /* Set before sending the message to prevent recursion */
    client->sessionState = UA_SESSIONSTATE_CLOSING;

    UA_CloseSessionRequest request;
    UA_CloseSessionRequest_init(&request);
    request.deleteSubscriptions = true;
    UA_StatusCode res =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
                              (UA_ClientAsyncServiceCallback)closeSessionCallback,
                              &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE], NULL, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        /* Sending the close request failed. Continue to close the connection
         * anyway. */
        cleanupSession(client);
        disconnectSecureChannel(client, false);
    }

    notifyClientState(client);
    unlockClient(client);
    return res;
}

/**** amalgamated original file "/src/client/ua_client_discovery.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


/* Helper method for additional warnings */
void
Client_warnEndpointsResult(UA_Client *client,
                           const UA_GetEndpointsResponse *response,
                           const UA_String *endpointUrl) {
    if(response->endpointsSize == 0) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "The server did not return any endpoints. "
                       "Did you use the correct endpointUrl?");
        return;
    }

    if(!UA_String_equal(endpointUrl, &response->endpoints[0].endpointUrl) ||
       (response->endpoints[0].server.discoveryUrlsSize > 0 &&
        !UA_String_equal(endpointUrl, &response->endpoints[0].server.discoveryUrls[0]))) {
        UA_String *betterUrl = &response->endpoints[0].endpointUrl;
        if(response->endpoints[0].server.discoveryUrlsSize > 0)
            betterUrl = &response->endpoints[0].server.discoveryUrls[0];
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "The server returned Endpoints with a different EndpointUrl %S than was "
                       "used to initialize the connection: %S. Some servers require a complete "
                       "match of the EndpointUrl/DiscoveryUrl (including the path) "
                       "to return all endpoints.", *betterUrl, *endpointUrl);
    }
}

/* Gets a list of endpoints. Memory is allocated for endpointDescription array */
static UA_StatusCode
getEndpointsInternal(UA_Client *client, const UA_String endpointUrl,
                     size_t *endpointDescriptionsSize,
                     UA_EndpointDescription **endpointDescriptions) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_GetEndpointsRequest request;
    UA_GetEndpointsRequest_init(&request);
    request.requestHeader.timeoutHint = 10000;
    // assume the endpointurl outlives the service call
    request.endpointUrl = endpointUrl;

    UA_GetEndpointsResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
                     &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);

    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_StatusCode retval = response.responseHeader.serviceResult;
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "GetEndpointRequest failed with error code %s",
                     UA_StatusCode_name(retval));
        UA_GetEndpointsResponse_clear(&response);
        return retval;
    }

    *endpointDescriptions = response.endpoints;
    *endpointDescriptionsSize = response.endpointsSize;
    response.endpoints = NULL;
    response.endpointsSize = 0;
    UA_GetEndpointsResponse_clear(&response);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
                       size_t *endpointDescriptionsSize,
                       UA_EndpointDescription** endpointDescriptions) {
    lockClient(client);

    UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    /* Client is already connected to a different server */
    if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl,
                            client->config.endpoint.endpointUrl.length) != 0) {
        unlockClient(client);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval;
    const UA_String url = UA_STRING((char*)(uintptr_t)serverUrl);
    if(!connected) {
        retval = connectSecureChannel(client, serverUrl);
        if(retval != UA_STATUSCODE_GOOD) {
            unlockClient(client);
            return retval;
        }
    }
    retval = getEndpointsInternal(client, url, endpointDescriptionsSize,
                                  endpointDescriptions);
    unlockClient(client);

    if(!connected)
        UA_Client_disconnect(client);
    return retval;
}

UA_StatusCode
UA_Client_findServers(UA_Client *client, const char *serverUrl,
                      size_t serverUrisSize, UA_String *serverUris,
                      size_t localeIdsSize, UA_String *localeIds,
                      size_t *registeredServersSize,
                      UA_ApplicationDescription **registeredServers) {
    lockClient(client);
    UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    /* Client is already connected to a different server */
    if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl,
                            client->config.endpoint.endpointUrl.length) != 0) {
        unlockClient(client);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval;
    if(!connected) {
        retval = connectSecureChannel(client, serverUrl);
        if(retval != UA_STATUSCODE_GOOD) {
            unlockClient(client);
            return retval;
        }
    }

    /* Prepare the request */
    UA_FindServersRequest request;
    UA_FindServersRequest_init(&request);
    request.serverUrisSize = serverUrisSize;
    request.serverUris = serverUris;
    request.localeIdsSize = localeIdsSize;
    request.localeIds = localeIds;

    /* Send the request */
    UA_FindServersResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST],
                     &response, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]);

    unlockClient(client);

    /* Process the response */
    retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        *registeredServersSize = response.serversSize;
        *registeredServers = response.servers;
        response.serversSize = 0;
        response.servers = NULL;
    } else {
        *registeredServersSize = 0;
        *registeredServers = NULL;
    }

    /* Clean up */
    UA_FindServersResponse_clear(&response);
    if(!connected)
        UA_Client_disconnect(client);
    return retval;
}

UA_StatusCode
UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl,
                               UA_UInt32 startingRecordId, UA_UInt32 maxRecordsToReturn,
                               size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter,
                               size_t *serverOnNetworkSize, UA_ServerOnNetwork **serverOnNetwork) {
    lockClient(client);

    UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    /* Client is already connected to a different server */
    if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl,
                            client->config.endpoint.endpointUrl.length) != 0) {
        unlockClient(client);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval;
    if(!connected) {
        retval = connectSecureChannel(client, serverUrl);
        if(retval != UA_STATUSCODE_GOOD) {
            unlockClient(client);
            return retval;
        }
    }

    /* Prepare the request */
    UA_FindServersOnNetworkRequest request;
    UA_FindServersOnNetworkRequest_init(&request);
    request.startingRecordId = startingRecordId;
    request.maxRecordsToReturn = maxRecordsToReturn;
    request.serverCapabilityFilterSize = serverCapabilityFilterSize;
    request.serverCapabilityFilter = serverCapabilityFilter;

    /* Send the request */
    UA_FindServersOnNetworkResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST],
                     &response, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]);

    unlockClient(client);

    /* Process the response */
    retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        *serverOnNetworkSize = response.serversSize;
        *serverOnNetwork = response.servers;
        response.serversSize = 0;
        response.servers = NULL;
    } else {
        *serverOnNetworkSize = 0;
        *serverOnNetwork = NULL;
    }

    /* Clean up */
    UA_FindServersOnNetworkResponse_clear(&response);
    if(!connected)
        UA_Client_disconnect(client);
    return retval;
}

/**** amalgamated original file "/src/client/ua_client_highlevel.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2016 (c) Chris Iatrou
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Fabian Arndt
 *    Copyright 2018 (c) Peter Rustler, basyskom GmbH
 */


UA_StatusCode
UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
                            UA_UInt16 *namespaceIndex) {
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    UA_ReadValueId id;
    UA_ReadValueId_init(&id);
    id.attributeId = UA_ATTRIBUTEID_VALUE;
    id.nodeId = UA_NS0ID(SERVER_NAMESPACEARRAY);
    request.nodesToRead = &id;
    request.nodesToReadSize = 1;

    UA_ReadResponse response = UA_Client_Service_read(client, request);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        retval = response.responseHeader.serviceResult;
    else if(response.resultsSize != 1 || !response.results[0].hasValue)
        retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
    else if(response.results[0].value.type != &UA_TYPES[UA_TYPES_STRING])
        retval = UA_STATUSCODE_BADTYPEMISMATCH;

    if(retval != UA_STATUSCODE_GOOD) {
        UA_ReadResponse_clear(&response);
        return retval;
    }

    retval = UA_STATUSCODE_BADNOTFOUND;
    UA_String *ns = (UA_String *)response.results[0].value.data;
    for(size_t i = 0; i < response.results[0].value.arrayLength; ++i) {
        if(UA_String_equal(namespaceUri, &ns[i])) {
            *namespaceIndex = (UA_UInt16)i;
            retval = UA_STATUSCODE_GOOD;
            break;
        }
    }

    UA_ReadResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId,
                               UA_NodeIteratorCallback callback, void *handle) {
    UA_BrowseRequest bReq;
    UA_BrowseRequest_init(&bReq);
    bReq.requestedMaxReferencesPerNode = 0;
    bReq.nodesToBrowse = UA_BrowseDescription_new();
    if(!bReq.nodesToBrowse)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    bReq.nodesToBrowseSize = 1;
    UA_NodeId_copy(&parentNodeId, &bReq.nodesToBrowse[0].nodeId);
    bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything
    bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;

    UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);

    UA_StatusCode retval = bResp.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        for(size_t i = 0; i < bResp.resultsSize; ++i) {
            for(size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
                UA_ReferenceDescription *ref = &bResp.results[i].references[j];
                retval |= callback(ref->nodeId.nodeId, !ref->isForward,
                                   ref->referenceTypeId, handle);
            }
        }
    }

    UA_BrowseRequest_clear(&bReq);
    UA_BrowseResponse_clear(&bResp);
    return retval;
}

/*******************/
/* Node Management */
/*******************/

UA_StatusCode
UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId,
                       const UA_NodeId referenceTypeId, UA_Boolean isForward,
                       const UA_String targetServerUri,
                       const UA_ExpandedNodeId targetNodeId,
                       UA_NodeClass targetNodeClass) {
    UA_AddReferencesItem item;
    UA_AddReferencesItem_init(&item);
    item.sourceNodeId = sourceNodeId;
    item.referenceTypeId = referenceTypeId;
    item.isForward = isForward;
    item.targetServerUri = targetServerUri;
    item.targetNodeId = targetNodeId;
    item.targetNodeClass = targetNodeClass;
    UA_AddReferencesRequest request;
    UA_AddReferencesRequest_init(&request);
    request.referencesToAdd = &item;
    request.referencesToAddSize = 1;
    UA_AddReferencesResponse response = UA_Client_Service_addReferences(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_AddReferencesResponse_clear(&response);
        return retval;
    }
    if(response.resultsSize != 1) {
        UA_AddReferencesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    retval = response.results[0];
    UA_AddReferencesResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId,
                          const UA_NodeId referenceTypeId, UA_Boolean isForward,
                          const UA_ExpandedNodeId targetNodeId,
                          UA_Boolean deleteBidirectional) {
    UA_DeleteReferencesItem item;
    UA_DeleteReferencesItem_init(&item);
    item.sourceNodeId = sourceNodeId;
    item.referenceTypeId = referenceTypeId;
    item.isForward = isForward;
    item.targetNodeId = targetNodeId;
    item.deleteBidirectional = deleteBidirectional;
    UA_DeleteReferencesRequest request;
    UA_DeleteReferencesRequest_init(&request);
    request.referencesToDelete = &item;
    request.referencesToDeleteSize = 1;
    UA_DeleteReferencesResponse response = UA_Client_Service_deleteReferences(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteReferencesResponse_clear(&response);
        return retval;
    }
    if(response.resultsSize != 1) {
        UA_DeleteReferencesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    retval = response.results[0];
    UA_DeleteReferencesResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
                     UA_Boolean deleteTargetReferences) {
    UA_DeleteNodesItem item;
    UA_DeleteNodesItem_init(&item);
    item.nodeId = nodeId;
    item.deleteTargetReferences = deleteTargetReferences;
    UA_DeleteNodesRequest request;
    UA_DeleteNodesRequest_init(&request);
    request.nodesToDelete = &item;
    request.nodesToDeleteSize = 1;
    UA_DeleteNodesResponse response = UA_Client_Service_deleteNodes(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteNodesResponse_clear(&response);
        return retval;
    }
    if(response.resultsSize != 1) {
        UA_DeleteNodesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    retval = response.results[0];
    UA_DeleteNodesResponse_clear(&response);
    return retval;
}

static UA_StatusCode
__Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
                 const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                 const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                 const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                 const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
    UA_AddNodesRequest request;
    UA_AddNodesRequest_init(&request);
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.parentNodeId.nodeId = parentNodeId;
    item.referenceTypeId = referenceTypeId;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.nodeClass = nodeClass;
    item.typeDefinition.nodeId = typeDefinition;
    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
    item.nodeAttributes.content.decoded.type = attributeType;
    item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr; // hack. is not written into.
    request.nodesToAdd = &item;
    request.nodesToAddSize = 1;
    UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);

    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_AddNodesResponse_clear(&response);
        return retval;
    }

    if(response.resultsSize != 1) {
        UA_AddNodesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }

    /* Move the id of the created node */
    retval = response.results[0].statusCode;
    if(retval == UA_STATUSCODE_GOOD && outNewNodeId) {
        *outNewNodeId = response.results[0].addedNodeId;
        UA_NodeId_init(&response.results[0].addedNodeId);
    }

    UA_AddNodesResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_addVariableNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
                          const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId,
                          const UA_QualifiedName browseName,
                          const UA_NodeId typeDefinition,
                          const UA_VariableAttributes attr,
                          UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_VARIABLE, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            typeDefinition, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId);
}

UA_StatusCode
UA_Client_addVariableTypeNode(UA_Client *client,
                              const UA_NodeId requestedNewNodeId,
                              const UA_NodeId parentNodeId,
                              const UA_NodeId referenceTypeId,
                              const UA_QualifiedName browseName,
                              const UA_VariableTypeAttributes attr,
                              UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], outNewNodeId);
}

UA_StatusCode
UA_Client_addObjectNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
                        const UA_NodeId parentNodeId,
                        const UA_NodeId referenceTypeId,
                        const UA_QualifiedName browseName,
                        const UA_NodeId typeDefinition,
                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_OBJECT, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            typeDefinition, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId);
}

UA_StatusCode
UA_Client_addObjectTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
                            const UA_NodeId parentNodeId,
                            const UA_NodeId referenceTypeId,
                            const UA_QualifiedName browseName,
                            const UA_ObjectTypeAttributes attr,
                            UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId);
}

UA_StatusCode
UA_Client_addViewNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
                      const UA_NodeId parentNodeId,
                      const UA_NodeId referenceTypeId,
                      const UA_QualifiedName browseName,
                      const UA_ViewAttributes attr,
                      UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_VIEW, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId);
}

UA_StatusCode
UA_Client_addReferenceTypeNode(UA_Client *client,
                               const UA_NodeId requestedNewNodeId,
                               const UA_NodeId parentNodeId,
                               const UA_NodeId referenceTypeId,
                               const UA_QualifiedName browseName,
                               const UA_ReferenceTypeAttributes attr,
                               UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId);
}

UA_StatusCode
UA_Client_addDataTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
                          const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId,
                          const UA_QualifiedName browseName,
                          const UA_DataTypeAttributes attr,
                          UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_DATATYPE, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId);
}

UA_StatusCode
UA_Client_addMethodNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
                        const UA_NodeId parentNodeId,
                        const UA_NodeId referenceTypeId,
                        const UA_QualifiedName browseName,
                        const UA_MethodAttributes attr,
                        UA_NodeId *outNewNodeId) {
    return __Client_addNode(client, UA_NODECLASS_METHOD, requestedNewNodeId,
                            parentNodeId, referenceTypeId, browseName,
                            UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId);
}

/********/
/* Call */
/********/

UA_StatusCode
UA_Client_call(UA_Client *client, const UA_NodeId objectId,
               const UA_NodeId methodId, size_t inputSize,
               const UA_Variant *input, size_t *outputSize,
               UA_Variant **output) {
    /* Set up the request */
    UA_CallRequest request;
    UA_CallRequest_init(&request);
    UA_CallMethodRequest item;
    UA_CallMethodRequest_init(&item);
    item.methodId = methodId;
    item.objectId = objectId;
    item.inputArguments = (UA_Variant *)(void*)(uintptr_t)input; // cast const...
    item.inputArgumentsSize = inputSize;
    request.methodsToCall = &item;
    request.methodsToCallSize = 1;

    /* Call the service */
    UA_CallResponse response = UA_Client_Service_call(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(response.resultsSize == 1)
            retval = response.results[0].statusCode;
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    if(UA_StatusCode_isBad(retval)) {
        UA_CallResponse_clear(&response);
        return retval;
    }

    /* Move the output arguments */
    if(output != NULL && outputSize != NULL) {
        *output = response.results[0].outputArguments;
        *outputSize = response.results[0].outputArgumentsSize;
        response.results[0].outputArguments = NULL;
        response.results[0].outputArgumentsSize = 0;
    }
    UA_CallResponse_clear(&response);
    return retval;
}

/**********/
/* Browse */
/**********/

UA_BrowseResult
UA_Client_browse(UA_Client *client, const UA_ViewDescription *view,
                 UA_UInt32 requestedMaxReferencesPerNode,
                 const UA_BrowseDescription *nodesToBrowse) {
    UA_BrowseResult res;
    UA_BrowseRequest request;
    UA_BrowseResponse response;
    UA_BrowseResponse_init(&response);
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(!nodesToBrowse) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto error;
    }

    /* Set up the request */
    UA_BrowseRequest_init(&request);
    if(view)
        request.view = *view;
    request.requestedMaxReferencesPerNode = requestedMaxReferencesPerNode;
    request.nodesToBrowse = (UA_BrowseDescription*)(uintptr_t)nodesToBrowse;
    request.nodesToBrowseSize = 1;

    /* Call the service */
    response = UA_Client_Service_browse(client, request);
    retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    if(UA_StatusCode_isBad(retval))
        goto error;

    /* Return the result */
    res = response.results[0];
    response.resultsSize = 0;
    UA_BrowseResponse_clear(&response);
    return res;

 error:
    UA_BrowseResponse_clear(&response);
    UA_BrowseResult_init(&res);
    res.statusCode = retval;
    return res;
}

UA_BrowseResult
UA_Client_browseNext(UA_Client *client, UA_Boolean releaseContinuationPoint,
                     UA_ByteString continuationPoint) {
    /* Set up the request */
    UA_BrowseNextRequest request;
    UA_BrowseNextRequest_init(&request);
    request.releaseContinuationPoints = releaseContinuationPoint;
    request.continuationPoints = &continuationPoint;
    request.continuationPointsSize = 1;

    /* Call the service */
    UA_BrowseResult res;
    UA_BrowseNextResponse response = UA_Client_Service_browseNext(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    if(UA_StatusCode_isBad(retval)) {
        UA_BrowseNextResponse_clear(&response);
        UA_BrowseResult_init(&res);
        res.statusCode = retval;
        return res;
    }

    /* Return the result */
    res = response.results[0];
    response.resultsSize = 0;
    UA_BrowseNextResponse_clear(&response);
    return res;
}

UA_BrowsePathResult
UA_Client_translateBrowsePathToNodeIds(UA_Client *client,
                                       const UA_BrowsePath *browsePath) {
    UA_BrowsePathResult res;
    UA_TranslateBrowsePathsToNodeIdsRequest request;
    UA_TranslateBrowsePathsToNodeIdsResponse response;
    UA_TranslateBrowsePathsToNodeIdsResponse_init(&response);
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(!browsePath) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto error;
    }

    /* Set up the request */
    UA_TranslateBrowsePathsToNodeIdsRequest_init(&request);
    request.browsePaths = (UA_BrowsePath*)(uintptr_t)browsePath;
    request.browsePathsSize = 1;

    /* Call the service */
    response = UA_Client_Service_translateBrowsePathsToNodeIds(client, request);
    retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    if(UA_StatusCode_isBad(retval))
        goto error;

    /* Return the result */
    res = response.results[0];
    response.resultsSize = 0;
    UA_TranslateBrowsePathsToNodeIdsResponse_clear(&response);
    return res;

 error:
    UA_TranslateBrowsePathsToNodeIdsResponse_clear(&response);
    UA_BrowsePathResult_init(&res);
    res.statusCode = retval;
    return res;
}

/********************/
/* Write Attributes */
/********************/

UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Client_write(UA_Client *client, const UA_WriteValue *wv) {
    if(!wv)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Set up the request */
    UA_WriteRequest request;
    UA_WriteRequest_init(&request);
    request.nodesToWrite = (UA_WriteValue*)(uintptr_t)wv;
    request.nodesToWriteSize = 1;

    /* Call the service */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_WriteResponse response = UA_Client_Service_write(client, request);
    retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    if(UA_StatusCode_isBad(retval)) {
        UA_WriteResponse_clear(&response);
        return retval;
    }

    /* Return the result */
    retval = response.results[0];
    UA_WriteResponse_clear(&response);
    return retval;
}

static UA_StatusCode
__Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,
                        UA_AttributeId attributeId, const void *in,
                        const UA_DataType *inDataType) {
    if(!in || !inDataType)
      return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_WriteValue wValue;
    UA_WriteValue_init(&wValue);
    wValue.nodeId = *nodeId;
    wValue.attributeId = attributeId;
    if(attributeId == UA_ATTRIBUTEID_VALUE &&
       inDataType == &UA_TYPES[UA_TYPES_VARIANT]) {
        wValue.value.value = *(const UA_Variant*)in;
        wValue.value.hasValue = true;
    } else if(attributeId == UA_ATTRIBUTEID_VALUE &&
              inDataType == &UA_TYPES[UA_TYPES_DATAVALUE]) {
        wValue.value = *(const UA_DataValue*)in;
    } else {
        /* Hack to get rid of the const annotation.
         * The value is never written into. */
        UA_Variant_setScalar(&wValue.value.value, (void*)(uintptr_t)in, inDataType);
        wValue.value.hasValue = true;
    }
    UA_WriteRequest wReq;
    UA_WriteRequest_init(&wReq);
    wReq.nodesToWrite = &wValue;
    wReq.nodesToWriteSize = 1;

    UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);

    UA_StatusCode retval = wResp.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(wResp.resultsSize == 1)
            retval = wResp.results[0];
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }

    UA_WriteResponse_clear(&wResp);
    return retval;
}

UA_StatusCode
UA_Client_writeNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId,
                               const UA_NodeId *newNodeId) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID,
                                   newNodeId, &UA_TYPES[UA_TYPES_NODEID]);
}

UA_StatusCode
UA_Client_writeNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId,
                                  const UA_NodeClass *newNodeClass) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,
                                   newNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]);
}

UA_StatusCode
UA_Client_writeBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   const UA_QualifiedName *newBrowseName) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
                                   newBrowseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
}

UA_StatusCode
UA_Client_writeDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId,
                                    const UA_LocalizedText *newDisplayName) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
                                   newDisplayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
}

UA_StatusCode
UA_Client_writeDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId,
                                    const UA_LocalizedText *newDescription) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
                                   newDescription, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
}

UA_StatusCode
UA_Client_writeWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
                                  const UA_UInt32 *newWriteMask) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
                                   newWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
}

UA_StatusCode
UA_Client_writeUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
                                      const UA_UInt32 *newUserWriteMask) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK,
                                   newUserWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
}

UA_StatusCode
UA_Client_writeIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   const UA_Boolean *newIsAbstract) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
                                   newIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_writeSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId,
                                  const UA_Boolean *newSymmetric) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
                                   newSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_writeInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
                                    const UA_LocalizedText *newInverseName) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
                                   newInverseName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
}

UA_StatusCode
UA_Client_writeContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId,
                                        const UA_Boolean *newContainsNoLoops) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
                                   newContainsNoLoops, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_writeEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId,
                                      const UA_Byte *newEventNotifier) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
                                   newEventNotifier, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
UA_Client_writeValueAttribute(UA_Client *client, const UA_NodeId nodeId,
                              const UA_Variant *newValue) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
                                   newValue, &UA_TYPES[UA_TYPES_VARIANT]);
}

UA_StatusCode
UA_Client_writeValueAttribute_scalar(UA_Client *client, const UA_NodeId nodeId,
                                     const void *newValue,
                                     const UA_DataType *valueType) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
                                   newValue, valueType);
}

UA_StatusCode
UA_Client_writeValueAttributeEx(UA_Client *client, const UA_NodeId nodeId,
                                const UA_DataValue *newValue) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
                                   newValue, &UA_TYPES[UA_TYPES_DATAVALUE]);
}

UA_StatusCode
UA_Client_writeDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId,
                                 const UA_NodeId *newDataType) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,
                                   newDataType, &UA_TYPES[UA_TYPES_NODEID]);
}

UA_StatusCode
UA_Client_writeValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
                                  const UA_Int32 *newValueRank) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,
                                   newValueRank, &UA_TYPES[UA_TYPES_INT32]);
}

UA_StatusCode
UA_Client_writeAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
                                    const UA_Byte *newAccessLevel) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
                                   newAccessLevel, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
UA_Client_writeAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId,
                                      UA_UInt32 *newAccessLevelEx) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
                                   newAccessLevelEx, &UA_TYPES[UA_TYPES_UINT32]);
}

UA_StatusCode
UA_Client_writeUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
                                        const UA_Byte *newUserAccessLevel) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL,
                                   newUserAccessLevel, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
UA_Client_writeMinimumSamplingIntervalAttribute(UA_Client *client,
                                                const UA_NodeId nodeId,
                                                const UA_Double *newMinInterval) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
                                   newMinInterval, &UA_TYPES[UA_TYPES_DOUBLE]);
}

UA_StatusCode
UA_Client_writeHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId,
                                    const UA_Boolean *newHistorizing) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
                                   newHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_writeExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   const UA_Boolean *newExecutable) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
                                   newExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_writeUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
                                       const UA_Boolean *newUserExecutable) {
    return __Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE,
                                   newUserExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
                                        size_t newArrayDimensionsSize,
                                        const UA_UInt32 *newArrayDimensions) {
    if(!newArrayDimensions)
      return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_WriteValue wValue;
    UA_WriteValue_init(&wValue);
    wValue.nodeId = nodeId;
    wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
    UA_Variant_setArray(&wValue.value.value, (void*)(uintptr_t)newArrayDimensions,
                        newArrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
    wValue.value.hasValue = true;
    UA_WriteRequest wReq;
    UA_WriteRequest_init(&wReq);
    wReq.nodesToWrite = &wValue;
    wReq.nodesToWriteSize = 1;

    UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);

    UA_StatusCode retval = wResp.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(wResp.resultsSize == 1)
            retval = wResp.results[0];
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    UA_WriteResponse_clear(&wResp);
    return retval;
}

/*******************/
/* Read Attributes */
/*******************/

UA_DataValue
UA_Client_read(UA_Client *client, const UA_ReadValueId *rvi) {
    /* Set up the request */
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
    request.nodesToRead = (UA_ReadValueId*)(uintptr_t)rvi;
    request.nodesToReadSize = 1;

    /* Call the service */
    UA_DataValue res;
    UA_ReadResponse response = UA_Client_Service_read(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    if(UA_StatusCode_isBad(retval)) {
        UA_ReadResponse_clear(&response);
        UA_DataValue_init(&res);
        res.status = retval;
        res.hasStatus = true;
        return res;
    }

    /* Return the result */
    res = response.results[0];
    response.resultsSize = 0;
    UA_ReadResponse_clear(&response);
    return res;
}

static UA_StatusCode
__Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
                       UA_AttributeId attributeId, void *out,
                       const UA_DataType *outDataType) {
    UA_ReadValueId item;
    UA_ReadValueId_init(&item);
    item.nodeId = *nodeId;
    item.attributeId = attributeId;
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = &item;
    request.nodesToReadSize = 1;
    UA_ReadResponse response = UA_Client_Service_read(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(response.resultsSize == 1)
            retval = response.results[0].status;
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD)) {
        UA_ReadResponse_clear(&response);
        return retval;
    }

    /* Set the StatusCode */
    UA_DataValue *res = response.results;
    if(res->hasStatus)
        retval = res->status;

    /* Return early of no value is given */
    if(!res->hasValue) {
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
        UA_ReadResponse_clear(&response);
        return retval;
    }

    /* Copy value into out */
    if(attributeId == UA_ATTRIBUTEID_VALUE) {
        memcpy(out, &res->value, sizeof(UA_Variant));
        UA_Variant_init(&res->value);
    } else if(attributeId == UA_ATTRIBUTEID_NODECLASS) {
        memcpy(out, (UA_NodeClass*)res->value.data, sizeof(UA_NodeClass));
    } else if(UA_Variant_isScalar(&res->value) &&
              res->value.type == outDataType) {
        memcpy(out, res->value.data, res->value.type->memSize);
        UA_free(res->value.data);
        res->value.data = NULL;
    } else {
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }

    UA_ReadResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_readNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId,
                              UA_NodeId *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID,
                                  out, &UA_TYPES[UA_TYPES_NODEID]);
}

UA_StatusCode
UA_Client_readNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId,
                                 UA_NodeClass *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,
                                  out, &UA_TYPES[UA_TYPES_NODECLASS]);
}

UA_StatusCode
UA_Client_readBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
                                  UA_QualifiedName *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
                                  out, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
}

UA_StatusCode
UA_Client_readDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   UA_LocalizedText *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
                                  out, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
}

UA_StatusCode
UA_Client_readDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   UA_LocalizedText *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
                                  out, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
}

UA_StatusCode
UA_Client_readWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
                                 UA_UInt32 *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
                                  out, &UA_TYPES[UA_TYPES_UINT32]);
}

UA_StatusCode
UA_Client_readUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,
                                     UA_UInt32 *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK,
                                  out, &UA_TYPES[UA_TYPES_UINT32]);
}

UA_StatusCode
UA_Client_readIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId,
                                  UA_Boolean *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
                                  out, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_readSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId,
                                 UA_Boolean *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
                                  out, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_readInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   UA_LocalizedText *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
                                  out, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
}

UA_StatusCode
UA_Client_readContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId,
                                       UA_Boolean *outContainsNoLoops) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
                                     outContainsNoLoops, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_readEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId,
                                     UA_Byte *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
                                  out, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
UA_Client_readValueAttribute(UA_Client *client, const UA_NodeId nodeId,
                             UA_Variant *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,
                                  out, &UA_TYPES[UA_TYPES_VARIANT]);
}

UA_StatusCode
UA_Client_readDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId,
                                UA_NodeId *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,
                                  out, &UA_TYPES[UA_TYPES_NODEID]);
}

UA_StatusCode
UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
                                 UA_Int32 *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,
                                  out, &UA_TYPES[UA_TYPES_INT32]);
}

UA_StatusCode
UA_Client_readAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   UA_Byte *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
                                  out, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
UA_Client_readAccessLevelExAttribute(UA_Client *client, const UA_NodeId nodeId,
                                     UA_UInt32 *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
                                  out, &UA_TYPES[UA_TYPES_UINT32]);
}

UA_StatusCode
UA_Client_readUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
                                       UA_Byte *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL,
                                  out, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
UA_Client_readMinimumSamplingIntervalAttribute(UA_Client *client, const UA_NodeId nodeId,
                                               UA_Double *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
                                  out, &UA_TYPES[UA_TYPES_DOUBLE]);
}

UA_StatusCode
UA_Client_readHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId,
                                   UA_Boolean *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
                                  out, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_readExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
                                  UA_Boolean *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
                                  out, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_readUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,
                                      UA_Boolean *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE,
                                  out, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

UA_StatusCode
UA_Client_readDatatypeDefinitionAttribute(UA_Client* client, const UA_NodeId nodeId,
                                          UA_StructureDefinition *out) {
    return __Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPEDEFINITION,
                                  out, &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]);
}

static UA_StatusCode
processReadArrayDimensionsResult(UA_ReadResponse *response,
                                 UA_UInt32 **outArrayDimensions,
                                 size_t *outArrayDimensionsSize) {
    UA_StatusCode retval = response->responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(response->resultsSize != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    retval = response->results[0].status;
    if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD))
        return retval;

    UA_DataValue *res = &response->results[0];
    if(!res->hasValue ||
       UA_Variant_isScalar(&res->value) ||
       res->value.type != &UA_TYPES[UA_TYPES_UINT32])
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Move results */
    *outArrayDimensions = (UA_UInt32*)res->value.data;
    *outArrayDimensionsSize = res->value.arrayLength;
    res->value.data = NULL;
    res->value.arrayLength = 0;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
                                       size_t *outArrayDimensionsSize,
                                       UA_UInt32 **outArrayDimensions) {
    UA_ReadValueId item;
    UA_ReadValueId_init(&item);
    item.nodeId = nodeId;
    item.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = &item;
    request.nodesToReadSize = 1;

    UA_ReadResponse response = UA_Client_Service_read(client, request);
    UA_StatusCode retval = processReadArrayDimensionsResult(&response, outArrayDimensions,
                                                            outArrayDimensionsSize);
    UA_ReadResponse_clear(&response);
    return retval;
}

/*********************/
/* Historical Access */
/*********************/
#ifdef UA_ENABLE_HISTORIZING

static UA_HistoryReadResponse
__UA_Client_HistoryRead(UA_Client *client, const UA_NodeId *nodeId,
                        UA_ExtensionObject* details, UA_String indexRange,
                        UA_TimestampsToReturn timestampsToReturn,
                        UA_ByteString continuationPoint, UA_Boolean releaseConti) {

    UA_HistoryReadValueId item;
    UA_HistoryReadValueId_init(&item);

    item.nodeId = *nodeId;
    item.indexRange = indexRange;
    item.continuationPoint = continuationPoint;
    item.dataEncoding = UA_QUALIFIEDNAME(0, NULL);

    UA_HistoryReadRequest request;
    UA_HistoryReadRequest_init(&request);

    request.nodesToRead = &item;
    request.nodesToReadSize = 1;
    request.timestampsToReturn = timestampsToReturn; // Defaults to Source
    request.releaseContinuationPoints = releaseConti; // No values are returned, if true

    /* Build ReadDetails */
    request.historyReadDetails = *details;

    return UA_Client_Service_historyRead(client, request);
}

static UA_StatusCode
__UA_Client_HistoryRead_service(UA_Client *client, const UA_NodeId *nodeId,
                                   const UA_HistoricalIteratorCallback callback,
                                   UA_ExtensionObject *details, UA_String indexRange,
                                   UA_TimestampsToReturn timestampsToReturn,
                                   void *callbackContext) {

    UA_ByteString continuationPoint = UA_BYTESTRING_NULL;
    UA_Boolean continuationAvail = false;
    UA_Boolean fetchMore = false;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    do {
        /* We release the continuation point, if no more data is requested by the user */
        UA_Boolean cleanup = !fetchMore && continuationAvail;
        UA_HistoryReadResponse response =
            __UA_Client_HistoryRead(client, nodeId, details, indexRange, timestampsToReturn, continuationPoint, cleanup);

        if(cleanup) {
            retval = response.responseHeader.serviceResult;
cleanup:    UA_HistoryReadResponse_clear(&response);
            UA_ByteString_clear(&continuationPoint);
            return retval;
        }

        retval = response.responseHeader.serviceResult;
        if(retval == UA_STATUSCODE_GOOD) {
            if(response.resultsSize == 1)
                retval = response.results[0].statusCode;
            else
                retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
        }
        if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD))
            goto cleanup;

        UA_HistoryReadResult *res = response.results;

        /* Clear old and check / store new continuation point */
        UA_ByteString_clear(&continuationPoint);
        UA_ByteString_copy(&res->continuationPoint, &continuationPoint);
        continuationAvail = !UA_ByteString_equal(&continuationPoint, &UA_BYTESTRING_NULL);

        /* Client callback with possibility to request further values */
        fetchMore = callback(client, nodeId, continuationAvail, &res->historyData, callbackContext);

        /* Regular cleanup */
        UA_HistoryReadResponse_clear(&response);
    } while(continuationAvail);

    return retval;
}

UA_StatusCode
UA_Client_HistoryRead_events(UA_Client *client, const UA_NodeId *nodeId,
                                const UA_HistoricalIteratorCallback callback,
                                UA_DateTime startTime, UA_DateTime endTime,
                                UA_String indexRange, const UA_EventFilter filter, UA_UInt32 numValuesPerNode,
                                UA_TimestampsToReturn timestampsToReturn, void *callbackContext) {

    UA_ReadEventDetails details;
    UA_ReadEventDetails_init(&details);
    details.filter = filter;

    // At least two of the following parameters must be set
    details.numValuesPerNode = numValuesPerNode; // 0 = return all / max server is capable of
    details.startTime = startTime;
    details.endTime = endTime;

    UA_ExtensionObject detailsExtensionObject;
    UA_ExtensionObject_init(&detailsExtensionObject);
    detailsExtensionObject.content.decoded.type = &UA_TYPES[UA_TYPES_READEVENTDETAILS];
    detailsExtensionObject.content.decoded.data = &details;
    detailsExtensionObject.encoding = UA_EXTENSIONOBJECT_DECODED;

    return __UA_Client_HistoryRead_service(client, nodeId, callback, &detailsExtensionObject,
                                              indexRange, timestampsToReturn, callbackContext);
}

static UA_StatusCode
__UA_Client_HistoryRead_service_rawMod(UA_Client *client, const UA_NodeId *nodeId,
                                          const UA_HistoricalIteratorCallback callback,
                                          UA_DateTime startTime,UA_DateTime endTime,
                                          UA_String indexRange, UA_Boolean returnBounds, UA_UInt32 numValuesPerNode,
                                          UA_Boolean readModified, UA_TimestampsToReturn timestampsToReturn,
                                          void *callbackContext) {

    UA_ReadRawModifiedDetails details;
    UA_ReadRawModifiedDetails_init(&details);
    details.isReadModified = readModified; // Return only modified values
    details.returnBounds = returnBounds;   // Return values pre / post given range

    // At least two of the following parameters must be set
    details.numValuesPerNode = numValuesPerNode;   // 0 = return all / max server is capable of
    details.startTime = startTime;
    details.endTime = endTime;

    UA_ExtensionObject detailsExtensionObject;
    UA_ExtensionObject_init(&detailsExtensionObject);
    detailsExtensionObject.content.decoded.type = &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS];
    detailsExtensionObject.content.decoded.data = &details;
    detailsExtensionObject.encoding = UA_EXTENSIONOBJECT_DECODED;

    return __UA_Client_HistoryRead_service(client, nodeId, callback,
                                              &detailsExtensionObject, indexRange,
                                              timestampsToReturn, callbackContext);
}

UA_StatusCode
UA_Client_HistoryRead_raw(UA_Client *client, const UA_NodeId *nodeId,
                             const UA_HistoricalIteratorCallback callback,
                             UA_DateTime startTime, UA_DateTime endTime,
                             UA_String indexRange, UA_Boolean returnBounds, UA_UInt32 numValuesPerNode,
                             UA_TimestampsToReturn timestampsToReturn, void *callbackContext) {

    return __UA_Client_HistoryRead_service_rawMod(client, nodeId, callback, startTime, endTime, indexRange, returnBounds,
                                                     numValuesPerNode, false, timestampsToReturn, callbackContext);
}

UA_StatusCode
UA_Client_HistoryRead_modified(UA_Client *client, const UA_NodeId *nodeId,
                                  const UA_HistoricalIteratorCallback callback,
                                  UA_DateTime startTime, UA_DateTime endTime,
                                  UA_String indexRange, UA_Boolean returnBounds, UA_UInt32 maxItems,
                                  UA_TimestampsToReturn timestampsToReturn, void *callbackContext) {
    return __UA_Client_HistoryRead_service_rawMod(client, nodeId, callback, startTime,
                                                  endTime, indexRange, returnBounds, maxItems,
                                                  true, timestampsToReturn, callbackContext);
}

static UA_HistoryUpdateResponse
__UA_Client_HistoryUpdate(UA_Client *client, void *details, size_t typeId) {
    UA_HistoryUpdateRequest request;
    UA_HistoryUpdateRequest_init(&request);

    UA_ExtensionObject extension;
    UA_ExtensionObject_init(&extension);
    request.historyUpdateDetailsSize = 1;
    request.historyUpdateDetails = &extension;

    extension.encoding = UA_EXTENSIONOBJECT_DECODED;
    extension.content.decoded.type = &UA_TYPES[typeId];
    extension.content.decoded.data = details;

    UA_HistoryUpdateResponse response;
    response = UA_Client_Service_historyUpdate(client, request);
    return response;
}

static UA_StatusCode
__UA_Client_HistoryUpdate_updateData(UA_Client *client, const UA_NodeId *nodeId,
                                     UA_PerformUpdateType type, UA_DataValue *value) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_UpdateDataDetails details;
    UA_UpdateDataDetails_init(&details);

    details.performInsertReplace = type;
    details.updateValuesSize = 1;
    details.updateValues = value;
    UA_NodeId_copy(nodeId, &details.nodeId);

    UA_HistoryUpdateResponse response;
    response = __UA_Client_HistoryUpdate(client, &details, UA_TYPES_UPDATEDATADETAILS);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        ret = response.responseHeader.serviceResult;
        goto cleanup;
    }
    if(response.resultsSize != 1 || response.results[0].operationResultsSize != 1) {
        ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
        goto cleanup;
    }
    if(response.results[0].statusCode != UA_STATUSCODE_GOOD) {
        ret = response.results[0].statusCode;
        goto cleanup;
    }
    ret = response.results[0].operationResults[0];
cleanup:
    UA_HistoryUpdateResponse_clear(&response);
    UA_NodeId_clear(&details.nodeId);
    return ret;
}

UA_StatusCode
UA_Client_HistoryUpdate_insert(UA_Client *client, const UA_NodeId *nodeId,
                               UA_DataValue *value) {
    return __UA_Client_HistoryUpdate_updateData(client, nodeId,
                                                UA_PERFORMUPDATETYPE_INSERT,
                                                value);
}

UA_StatusCode
UA_Client_HistoryUpdate_replace(UA_Client *client, const UA_NodeId *nodeId,
                                UA_DataValue *value) {
    return __UA_Client_HistoryUpdate_updateData(client, nodeId,
                                                UA_PERFORMUPDATETYPE_REPLACE,
                                                value);
}

UA_StatusCode
UA_Client_HistoryUpdate_update(UA_Client *client, const UA_NodeId *nodeId,
                               UA_DataValue *value) {
    return __UA_Client_HistoryUpdate_updateData(client, nodeId,
                                                UA_PERFORMUPDATETYPE_UPDATE,
                                                value);
}

UA_StatusCode
UA_Client_HistoryUpdate_deleteRaw(UA_Client *client, const UA_NodeId *nodeId,
                                  UA_DateTime startTimestamp, UA_DateTime endTimestamp) {
    UA_DeleteRawModifiedDetails details;
    UA_DeleteRawModifiedDetails_init(&details);
    details.isDeleteModified = false;
    details.startTime = startTimestamp;
    details.endTime = endTimestamp;
    UA_NodeId_copy(nodeId, &details.nodeId);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_HistoryUpdateResponse response;
    response = __UA_Client_HistoryUpdate(client, &details, UA_TYPES_DELETERAWMODIFIEDDETAILS);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        ret = response.responseHeader.serviceResult;
        goto cleanup;
    }
    if(response.resultsSize != 1) {
        ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
        goto cleanup;
    }

    ret = response.results[0].statusCode;

cleanup:
    UA_HistoryUpdateResponse_clear(&response);
    UA_NodeId_clear(&details.nodeId);
    return ret;
}

#endif

/*******************/
/* Async Functions */
/*******************/

static UA_StatusCode
__UA_Client_writeAttribute_async(UA_Client *client, const UA_NodeId *nodeId,
                                 UA_AttributeId attributeId, const void *in,
                                 const UA_DataType *inDataType,
                                 UA_ClientAsyncServiceCallback callback,
                                 void *userdata, UA_UInt32 *reqId) {
    if(!in)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_WriteValue wValue;
    UA_WriteValue_init(&wValue);
    wValue.nodeId = *nodeId;
    wValue.attributeId = attributeId;
    if(attributeId == UA_ATTRIBUTEID_VALUE)
        wValue.value.value = *(const UA_Variant*) in;
    else
        /* hack. is never written into. */
        UA_Variant_setScalar(&wValue.value.value, (void*) (uintptr_t) in,
                inDataType);
    wValue.value.hasValue = true;
    UA_WriteRequest wReq;
    UA_WriteRequest_init(&wReq);
    wReq.nodesToWrite = &wValue;
    wReq.nodesToWriteSize = 1;

    return __UA_Client_AsyncService(client, &wReq,
                                    &UA_TYPES[UA_TYPES_WRITEREQUEST], callback,
                                    &UA_TYPES[UA_TYPES_WRITERESPONSE], userdata, reqId);
}

UA_StatusCode
UA_Client_call_async(UA_Client *client, const UA_NodeId objectId,
                     const UA_NodeId methodId, size_t inputSize,
                     const UA_Variant *input,
                     UA_ClientAsyncCallCallback callback,
                     void *userdata, UA_UInt32 *reqId) {
    UA_CallRequest request;
    UA_CallRequest_init(&request);
    UA_CallMethodRequest item;
    UA_CallMethodRequest_init(&item);
    item.objectId = objectId;
    item.methodId = methodId;
    item.inputArguments = (UA_Variant *)(uintptr_t)input; /* cast const */
    item.inputArgumentsSize = inputSize;
    request.methodsToCall = &item;
    request.methodsToCallSize = 1;
    return __UA_Client_AsyncService(client, &request,
            &UA_TYPES[UA_TYPES_CALLREQUEST], (UA_ClientAsyncServiceCallback)callback,
            &UA_TYPES[UA_TYPES_CALLRESPONSE], userdata, reqId);
}

/*************************/
/* Read Single Attribute */
/*************************/

typedef struct {
    UA_ClientAsyncOperationCallback userCallback;
    void *userContext;
    const UA_DataType *resultType; /* DataValue -> Value attribute,
                                    * Variant -> ArrayDimensions attribute */
} UA_AttributeReadContext;

static void
AttributeReadCallback(UA_Client *client, void *userdata,
                      UA_UInt32 requestId, UA_ReadResponse *rr) {
    UA_AttributeReadContext *ctx = (UA_AttributeReadContext*)userdata;
    UA_LOG_DEBUG(UA_Client_getConfig(client)->logging, UA_LOGCATEGORY_CLIENT,
                "Async read response for request %" PRIu32, requestId);

    UA_DataValue *dv = NULL;

    /* Check the ServiceResult */
    UA_StatusCode res = rr->responseHeader.serviceResult;
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Check result array size */
    if(rr->resultsSize != 1) {
        res = UA_STATUSCODE_BADINTERNALERROR;
        goto finish;
    }

    /* A Value attribute */
    dv = &rr->results[0];
    if(ctx->resultType == &UA_TYPES[UA_TYPES_DATAVALUE]) {
        ctx->userCallback(client, ctx->userContext, requestId,
                          UA_STATUSCODE_GOOD, dv);
        goto finish;
    }

    /* An ArrayDimensions attribute. Has to be an array of UInt32. */
    if(ctx->resultType == &UA_TYPES[UA_TYPES_VARIANT]) {
        if(dv->hasValue &&
           UA_Variant_hasArrayType(&dv->value, &UA_TYPES[UA_TYPES_UINT32])) {
            ctx->userCallback(client, ctx->userContext, requestId,
                              UA_STATUSCODE_GOOD, &dv->value);
        } else {
            res = UA_STATUSCODE_BADINTERNALERROR;
        }
        goto finish;
    }

    /* Check we have a value */
    if(!dv->hasValue) {
        res = UA_STATUSCODE_BADINTERNALERROR;
        goto finish;
    }

    /* Check the type. Try to adjust "in situ" if no match. */
    if(!UA_Variant_hasScalarType(&dv->value, ctx->resultType)) {
        /* Remember the old pointer, adjustType can "unwrap" a type but won't
         * free the wrapper. Because the server code still keeps the wrapper. */
        void *oldVal = dv->value.data;
        adjustType(&dv->value, ctx->resultType);
        if(dv->value.data != oldVal)
            UA_free(oldVal);
        if(!UA_Variant_hasScalarType(&dv->value, ctx->resultType)) {
            res = UA_STATUSCODE_BADINTERNALERROR;
            goto finish;
        }
    }

    /* Callback into userland */
    ctx->userCallback(client, ctx->userContext, requestId,
                      UA_STATUSCODE_GOOD, dv->value.data);

 finish:
    if(res != UA_STATUSCODE_GOOD)
        ctx->userCallback(client, ctx->userContext, requestId, res, NULL);
    UA_free(ctx);
}

static UA_StatusCode
readAttribute_async(UA_Client *client, const UA_ReadValueId *rvi,
                    UA_TimestampsToReturn timestampsToReturn,
                    const UA_DataType *resultType, /* For the specialized reads */
                    UA_ClientAsyncOperationCallback callback,
                    void *userdata, UA_UInt32 *requestId) {
    UA_AttributeReadContext *ctx = (UA_AttributeReadContext*)
        UA_malloc(sizeof(UA_AttributeReadContext));
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    ctx->userCallback = callback;
    ctx->userContext = userdata;
    ctx->resultType = resultType;

    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = (UA_ReadValueId*)(uintptr_t)rvi; /* hack, treated as const */
    request.nodesToReadSize = 1;
    request.timestampsToReturn = timestampsToReturn;

    UA_StatusCode res =
        __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
                                 (UA_ClientAsyncServiceCallback)AttributeReadCallback,
                                 &UA_TYPES[UA_TYPES_READRESPONSE], ctx, requestId);
    if(res != UA_STATUSCODE_GOOD)
        UA_free(ctx);
    return res;
}

UA_StatusCode
UA_Client_readAttribute_async(UA_Client *client, const UA_ReadValueId *rvi,
                              UA_TimestampsToReturn timestampsToReturn,
                              UA_ClientAsyncReadAttributeCallback callback,
                              void *userdata, UA_UInt32 *requestId) {
    return readAttribute_async(client, rvi, timestampsToReturn,
                               &UA_TYPES[UA_TYPES_DATAVALUE], /* special handling */
                               (UA_ClientAsyncOperationCallback)callback,
                               userdata, requestId);
}

/* Helper to keep the code short */
static UA_StatusCode
readAttribute_simpleAsync(UA_Client *client, const UA_NodeId *nodeId,
                          UA_AttributeId attributeId, const UA_DataType *resultType,
                          UA_ClientAsyncOperationCallback callback,
                          void *userdata, UA_UInt32 *requestId) {
    UA_ReadValueId rvi;
    UA_ReadValueId_init(&rvi);
    rvi.nodeId = *nodeId;
    rvi.attributeId = attributeId;
    return readAttribute_async(client, &rvi, UA_TIMESTAMPSTORETURN_NEITHER,
                               resultType, callback, userdata, requestId);
}

UA_StatusCode
UA_Client_readValueAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                   UA_ClientAsyncReadValueAttributeCallback callback,
                                   void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_VALUE,
                                     &UA_TYPES[UA_TYPES_DATAVALUE], /* special hndling */
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readDataTypeAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                      UA_ClientAsyncReadDataTypeAttributeCallback callback,
                                      void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,
                                     &UA_TYPES[UA_TYPES_NODEID],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readArrayDimensionsAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                             UA_ClientReadArrayDimensionsAttributeCallback callback,
                                             void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
                                     &UA_TYPES[UA_TYPES_VARIANT], /* special handling */
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readNodeClassAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadNodeClassAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,
                                     &UA_TYPES[UA_TYPES_NODECLASS],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readBrowseNameAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                        UA_ClientAsyncReadBrowseNameAttributeCallback callback,
                                        void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
                                     &UA_TYPES[UA_TYPES_QUALIFIEDNAME],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readDisplayNameAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadDisplayNameAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readDescriptionAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadDescriptionAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readWriteMaskAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadWriteMaskAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
                                     &UA_TYPES[UA_TYPES_UINT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode UA_EXPORT
UA_Client_readUserWriteMaskAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                           UA_ClientAsyncReadUserWriteMaskAttributeCallback callback,
                                           void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK,
                                     &UA_TYPES[UA_TYPES_UINT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readIsAbstractAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                        UA_ClientAsyncReadIsAbstractAttributeCallback callback,
                                        void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readSymmetricAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadSymmetricAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readInverseNameAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadInverseNameAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readContainsNoLoopsAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                             UA_ClientAsyncReadContainsNoLoopsAttributeCallback callback,
                                             void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readEventNotifierAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                           UA_ClientAsyncReadEventNotifierAttributeCallback callback,
                                           void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
                                     &UA_TYPES[UA_TYPES_BYTE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readValueRankAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadValueRankAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,
                                     &UA_TYPES[UA_TYPES_INT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readAccessLevelAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadAccessLevelAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
                                     &UA_TYPES[UA_TYPES_BYTE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readAccessLevelExAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                           UA_ClientAsyncReadAccessLevelExAttributeCallback callback,
                                           void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
                                     &UA_TYPES[UA_TYPES_UINT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readUserAccessLevelAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                             UA_ClientAsyncReadUserAccessLevelAttributeCallback callback,
                                             void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL,
                                     &UA_TYPES[UA_TYPES_BYTE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readMinimumSamplingIntervalAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                                     UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback callback,
                                                     void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
                                     &UA_TYPES[UA_TYPES_DOUBLE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readHistorizingAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadHistorizingAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readExecutableAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                        UA_ClientAsyncReadExecutableAttributeCallback callback,
                                        void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readUserExecutableAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                            UA_ClientAsyncReadUserExecutableAttributeCallback callback,
                                            void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

static UA_StatusCode
__UA_Client_addNode_async(UA_Client *client, const UA_NodeClass nodeClass,
                          const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                          const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                          const UA_DataType *attributeType, UA_NodeId *outNewNodeId,
                          UA_ClientAsyncServiceCallback callback, void *userdata,
                          UA_UInt32 *reqId) {
    UA_AddNodesRequest request;
    UA_AddNodesRequest_init(&request);
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.parentNodeId.nodeId = parentNodeId;
    item.referenceTypeId = referenceTypeId;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.nodeClass = nodeClass;
    item.typeDefinition.nodeId = typeDefinition;
    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
    item.nodeAttributes.content.decoded.type = attributeType;
    item.nodeAttributes.content.decoded.data = (void*) (uintptr_t) attr; // hack. is not written into.
    request.nodesToAdd = &item;
    request.nodesToAddSize = 1;

    return __UA_Client_AsyncService(client, &request,
            &UA_TYPES[UA_TYPES_ADDNODESREQUEST], callback,
            &UA_TYPES[UA_TYPES_ADDNODESRESPONSE], userdata, reqId);

}

UA_StatusCode
UA_Client_addVariableNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                                const UA_VariableAttributes attr, UA_NodeId *outNewNodeId,
                                UA_ClientAsyncAddNodesCallback callback, void *userdata,
                                UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

UA_StatusCode
UA_Client_addVariableTypeNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                                    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                    const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
                                    UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
                                    void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

UA_StatusCode
UA_Client_addObjectNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                              const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                              const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId,
                              UA_ClientAsyncAddNodesCallback callback, void *userdata,
                              UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

UA_StatusCode
UA_Client_addObjectTypeNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                                  const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                  const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
                                  UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
                                  void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

UA_StatusCode
UA_Client_addViewNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                            const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                            const UA_QualifiedName browseName, const UA_ViewAttributes attr,
                            UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
                            void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

UA_StatusCode
UA_Client_addReferenceTypeNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                     const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
                                     UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
                                     void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, UA_NODEID_NULL,
                                     (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

UA_StatusCode
UA_Client_addDataTypeNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
                                UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
                                void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

UA_StatusCode
UA_Client_addMethodNode_async(UA_Client *client, const UA_NodeId requestedNewNodeId,
                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                              const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                              UA_NodeId *outNewNodeId, UA_ClientAsyncAddNodesCallback callback,
                              void *userdata, UA_UInt32 *reqId) {
    return __UA_Client_addNode_async(client, UA_NODECLASS_METHOD, requestedNewNodeId, parentNodeId,
                                     referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes *)&attr,
                                     &UA_TYPES[UA_TYPES_METHODATTRIBUTES], outNewNodeId,
                                     (UA_ClientAsyncServiceCallback)callback, userdata, reqId);
}

#define UA_CLIENT_ASYNCWRITE_IMPL(NAME, ATTR_ID, ATTR_TYPE, ATTR_TYPEDESC)                               \
    UA_StatusCode NAME(UA_Client *client, const UA_NodeId nodeId,                                        \
                       const ATTR_TYPE *attr, UA_ClientAsyncWriteCallback callback,                      \
                       void *userdata, UA_UInt32 *reqId) {                                               \
        return __UA_Client_writeAttribute_async(client, &nodeId, UA_ATTRIBUTEID_##ATTR_ID, attr,           \
                                                &UA_TYPES[UA_TYPES_##ATTR_TYPEDESC], \
                                                (UA_ClientAsyncServiceCallback)callback, userdata, reqId); \
}

UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeNodeIdAttribute_async, NODEID, UA_NodeId, NODEID)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeNodeClassAttribute_async, NODECLASS, UA_NodeClass, NODECLASS)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeBrowseNameAttribute_async, BROWSENAME, UA_QualifiedName, QUALIFIEDNAME)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeDisplayNameAttribute_async, DISPLAYNAME, UA_LocalizedText, LOCALIZEDTEXT)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeDescriptionAttribute_async, DESCRIPTION, UA_LocalizedText, LOCALIZEDTEXT)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeWriteMaskAttribute_async, WRITEMASK, UA_UInt32, UINT32)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeIsAbstractAttribute_async, ISABSTRACT, UA_Boolean, BOOLEAN)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeSymmetricAttribute_async, SYMMETRIC, UA_Boolean, BOOLEAN)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeInverseNameAttribute_async, INVERSENAME, UA_LocalizedText, LOCALIZEDTEXT)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeContainsNoLoopsAttribute_async, CONTAINSNOLOOPS, UA_Boolean, BOOLEAN)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeEventNotifierAttribute_async, EVENTNOTIFIER, UA_Byte, BYTE)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeValueAttribute_async, VALUE, UA_Variant, VARIANT)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeDataTypeAttribute_async, DATATYPE, UA_NodeId, NODEID)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeValueRankAttribute_async, VALUERANK, UA_Int32, INT32)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeAccessLevelAttribute_async, ACCESSLEVEL, UA_Byte, BYTE)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeMinimumSamplingIntervalAttribute_async, MINIMUMSAMPLINGINTERVAL, UA_Double, DOUBLE)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeHistorizingAttribute_async, HISTORIZING, UA_Boolean, BOOLEAN)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeExecutableAttribute_async, EXECUTABLE, UA_Boolean, BOOLEAN)
UA_CLIENT_ASYNCWRITE_IMPL(UA_Client_writeAccessLevelExAttribute_async, ACCESSLEVELEX, UA_UInt32, UINT32)

/**** amalgamated original file "/src/client/ua_client_subscriptions.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Sten Grüner
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2017 (c) Frank Meerkötter
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */



struct UA_Client_MonitoredItem_ForDelete {
    UA_Client *client;
    UA_Client_Subscription *sub;
    UA_UInt32 *monitoredItemId;
};

/*****************/
/* Subscriptions */
/*****************/

/* For ZIP_TREE we use clientHandle comparison */
static enum ZIP_CMP
UA_ClientHandle_cmp(const void *a, const void *b) {
    const UA_Client_MonitoredItem *aa = (const UA_Client_MonitoredItem *)a;
    const UA_Client_MonitoredItem *bb = (const UA_Client_MonitoredItem *)b;
    if(aa->clientHandle < bb->clientHandle)
        return ZIP_CMP_LESS;
    if(aa->clientHandle > bb->clientHandle)
        return ZIP_CMP_MORE;
    return ZIP_CMP_EQ;
}

ZIP_FUNCTIONS(MonitorItemsTree, UA_Client_MonitoredItem, zipfields,
              UA_Client_MonitoredItem, zipfields, UA_ClientHandle_cmp)

static void
MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub,
                     UA_Client_MonitoredItem *mon);

static void
Subscription_create(UA_Client *client, UA_Client_Subscription *newSub,
                    UA_CreateSubscriptionResponse *response) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_EventLoop *el = client->config.eventLoop;

    newSub->subscriptionId = response->subscriptionId;
    newSub->sequenceNumber = 0;
    newSub->lastActivity = el->dateTime_nowMonotonic(el);
    newSub->publishingInterval = response->revisedPublishingInterval;
    newSub->maxKeepAliveCount = response->revisedMaxKeepAliveCount;
    ZIP_INIT(&newSub->monitoredItems);
    LIST_INSERT_HEAD(&client->subscriptions, newSub, listEntry);

    /* Immediately send the first publish requests if there are none
     * outstanding */
    __Client_Subscriptions_backgroundPublish(client);
}

static void
Subscriptions_create_handler(UA_Client *client, void *data,
                             UA_UInt32 requestId, void *r) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_CreateSubscriptionResponse *response = (UA_CreateSubscriptionResponse *)r;
    CustomCallback *cc = (CustomCallback *)data;
    UA_Client_Subscription *newSub = (UA_Client_Subscription *)cc->clientData;
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_free(newSub);
        goto cleanup;
    }

    /* Prepare the internal representation */
    Subscription_create(client, newSub, response);

cleanup:
    if(cc->userCallback)
        cc->userCallback(client, cc->userData, requestId, response);
    UA_free(cc);
}

UA_CreateSubscriptionResponse
UA_Client_Subscriptions_create(UA_Client *client,
                               const UA_CreateSubscriptionRequest request,
                               void *subscriptionContext,
                               UA_Client_StatusChangeNotificationCallback statusChangeCallback,
                               UA_Client_DeleteSubscriptionCallback deleteCallback) {
    lockClient(client);

    UA_CreateSubscriptionResponse response;
    UA_Client_Subscription *sub = (UA_Client_Subscription *)
        UA_malloc(sizeof(UA_Client_Subscription));
    if(!sub) {
        UA_CreateSubscriptionResponse_init(&response);
        response.responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        unlockClient(client);
        return response;
    }
    sub->context = subscriptionContext;
    sub->statusChangeCallback = statusChangeCallback;
    sub->deleteCallback = deleteCallback;

    /* Send the request as a synchronous service call */
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
                     &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_free(sub);
        unlockClient(client);
        return response;
    }

    Subscription_create(client, sub, &response);

    unlockClient(client);
    return response;
}

UA_StatusCode
UA_Client_Subscriptions_create_async(UA_Client *client, const UA_CreateSubscriptionRequest request,
                                     void *subscriptionContext,
                                     UA_Client_StatusChangeNotificationCallback statusChangeCallback,
                                     UA_Client_DeleteSubscriptionCallback deleteCallback,
                                     UA_ClientAsyncCreateSubscriptionCallback createCallback,
                                     void *userdata, UA_UInt32 *requestId) {
    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
    if(!cc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_Client_Subscription *sub = (UA_Client_Subscription *)
        UA_malloc(sizeof(UA_Client_Subscription));
    if(!sub) {
        UA_free(cc);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    sub->context = subscriptionContext;
    sub->statusChangeCallback = statusChangeCallback;
    sub->deleteCallback = deleteCallback;

    cc->userCallback = (UA_ClientAsyncServiceCallback)createCallback;
    cc->userData = userdata;
    cc->clientData = sub;

    /* Send the request as asynchronous service call */
    UA_StatusCode res =
        __UA_Client_AsyncService(client, &request,
                                 &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
                                 Subscriptions_create_handler,
                                 &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE],
                                 cc, requestId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(cc);
        UA_free(sub);
    }
    return res;
}

static UA_Client_Subscription *
findSubscriptionById(const UA_Client *client, UA_UInt32 subscriptionId) {
    UA_Client_Subscription *sub = NULL;
    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
        if(sub->subscriptionId == subscriptionId)
            break;
    }
    return sub;
}

static void
Subscription_modify(UA_Client *client, UA_Client_Subscription *sub,
                    const UA_ModifySubscriptionResponse *response) {
    sub->publishingInterval = response->revisedPublishingInterval;
    sub->maxKeepAliveCount = response->revisedMaxKeepAliveCount;
}

static void
Subscription_modify_handler(UA_Client *client, void *data,
                            UA_UInt32 requestId, void *r) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_ModifySubscriptionResponse *response = (UA_ModifySubscriptionResponse *)r;
    CustomCallback *cc = (CustomCallback *)data;
    UA_Client_Subscription *sub =
        findSubscriptionById(client, (UA_UInt32)(uintptr_t)cc->clientData);
    if(sub) {
        Subscription_modify(client, sub, response);
    } else {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "No internal representation of subscription %" PRIu32,
                    (UA_UInt32)(uintptr_t)cc->clientData);
    }

    if(cc->userCallback)
        cc->userCallback(client, cc->userData, requestId, response);
    UA_free(cc);
}

UA_StatusCode
UA_Client_Subscriptions_getContext(UA_Client *client, UA_UInt32 subscriptionId,
                                   void **subContext) {
    if(!client || !subContext)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockClient(client);
    UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
    if(!sub) {
        unlockClient(client);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    *subContext = sub->context;
    unlockClient(client);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_Subscriptions_setContext(UA_Client *client, UA_UInt32 subscriptionId,
                                   void *subContext) {
    if(!client)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockClient(client);
    UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
    if(!sub) {
        unlockClient(client);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    sub->context = subContext;
    unlockClient(client);
    return UA_STATUSCODE_GOOD;
}

UA_ModifySubscriptionResponse
UA_Client_Subscriptions_modify(UA_Client *client,
                               const UA_ModifySubscriptionRequest request) {
    UA_ModifySubscriptionResponse response;
    UA_ModifySubscriptionResponse_init(&response);

    /* Find the internal representation */
    lockClient(client);
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
    if(!sub) {
        unlockClient(client);
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return response;
    }

    /* Call the service */
    __Client_Service(client,
                     &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
                     &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]);

    /* Adjust the internal representation. Lookup again for thread-safety. */
    sub = findSubscriptionById(client, request.subscriptionId);
    if(!sub) {
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        unlockClient(client);
        return response;
    }
    Subscription_modify(client, sub, &response);
    unlockClient(client);
    return response;
}

UA_StatusCode
UA_Client_Subscriptions_modify_async(UA_Client *client,
                                     const UA_ModifySubscriptionRequest request,
                                     UA_ClientAsyncModifySubscriptionCallback callback,
                                     void *userdata, UA_UInt32 *requestId) {
    lockClient(client);

    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
    if(!sub) {
        unlockClient(client);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
    if(!cc) {
        unlockClient(client);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    cc->clientData = (void *)(uintptr_t)request.subscriptionId;
    cc->userData = userdata;
    cc->userCallback = (UA_ClientAsyncServiceCallback)callback;

    UA_StatusCode res =
        __Client_AsyncService(client, &request,
                              &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
                              Subscription_modify_handler,
                              &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE],
                              cc, requestId);

    unlockClient(client);
    return res;
}

static void *
MonitoredItem_delete_wrapper(void *data, UA_Client_MonitoredItem *mon) {
    struct UA_Client_MonitoredItem_ForDelete *deleteMonitoredItem =
        (struct UA_Client_MonitoredItem_ForDelete *)data;
    if(deleteMonitoredItem != NULL) {
        if(deleteMonitoredItem->monitoredItemId != NULL &&
           (mon->monitoredItemId != *deleteMonitoredItem->monitoredItemId)) {
            return NULL;
        }
        MonitoredItem_delete(deleteMonitoredItem->client, deleteMonitoredItem->sub, mon);
    }
    return NULL;
}

static void
__Client_Subscription_deleteInternal(UA_Client *client,
                                     UA_Client_Subscription *sub) {
    /* Remove the MonitoredItems */
    struct UA_Client_MonitoredItem_ForDelete deleteMonitoredItem;
    memset(&deleteMonitoredItem, 0, sizeof(struct UA_Client_MonitoredItem_ForDelete));
    deleteMonitoredItem.client = client;
    deleteMonitoredItem.sub = sub;
    ZIP_ITER(MonitorItemsTree, &sub->monitoredItems,
             MonitoredItem_delete_wrapper, &deleteMonitoredItem);

    /* Call the delete callback */
    if(sub->deleteCallback) {
        void *subC = sub->context;
        UA_UInt32 subId = sub->subscriptionId;
        sub->deleteCallback(client, subId, subC);
    }

    /* Remove */
    LIST_REMOVE(sub, listEntry);
    UA_free(sub);
}

static void
__Client_Subscription_processDelete(UA_Client *client,
                                    const UA_DeleteSubscriptionsRequest *request,
                                    const UA_DeleteSubscriptionsResponse *response)  {
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return;

    /* Check that the request and response size -- use the same index for both */
    if(request->subscriptionIdsSize != response->resultsSize)
        return;

    for(size_t i = 0; i < request->subscriptionIdsSize; i++) {
        if(response->results[i] != UA_STATUSCODE_GOOD &&
           response->results[i] != UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID)
            continue;

        /* Get the Subscription */
        UA_Client_Subscription *sub =
            findSubscriptionById(client, request->subscriptionIds[i]);
        if(!sub) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "No internal representation of subscription %" PRIu32,
                        request->subscriptionIds[i]);
            continue;
        }

        /* Delete the Subscription */
        __Client_Subscription_deleteInternal(client, sub);
    }
}

typedef struct {
    UA_DeleteSubscriptionsRequest request;
    UA_ClientAsyncServiceCallback userCallback;
    void *userData;
} DeleteSubscriptionCallback;

static void
Subscriptions_delete_handler(UA_Client *client, void *data,
                             UA_UInt32 requestId, void *r) {
    UA_DeleteSubscriptionsResponse *response =
        (UA_DeleteSubscriptionsResponse *)r;
    DeleteSubscriptionCallback *dsc =
        (DeleteSubscriptionCallback*)data;

    lockClient(client);

    /* Delete */
    __Client_Subscription_processDelete(client, &dsc->request, response);

    /* Userland Callback */
    if(dsc->userCallback)
        dsc->userCallback(client, dsc->userData, requestId, response);

    /* Cleanup */
    UA_DeleteSubscriptionsRequest_clear(&dsc->request);
    UA_free(dsc);

    unlockClient(client);
}

UA_StatusCode
UA_Client_Subscriptions_delete_async(UA_Client *client,
                                     const UA_DeleteSubscriptionsRequest request,
                                     UA_ClientAsyncDeleteSubscriptionsCallback callback,
                                     void *userdata, UA_UInt32 *requestId) {
    /* Make a copy of the request that persists into the async callback */
    DeleteSubscriptionCallback *dsc = (DeleteSubscriptionCallback*)
        UA_malloc(sizeof(DeleteSubscriptionCallback));
    if(!dsc)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    dsc->userCallback = (UA_ClientAsyncServiceCallback)callback;
    dsc->userData = userdata;
    UA_StatusCode res = UA_DeleteSubscriptionsRequest_copy(&request, &dsc->request);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(dsc);
        return res;
    }

    /* Make the async call */
    res = __UA_Client_AsyncService(client, &request,
                                   &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
                                   Subscriptions_delete_handler,
                                   &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE],
                                   dsc, requestId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_DeleteSubscriptionsRequest_clear(&dsc->request);
        UA_free(dsc);
    }
    return res;
}

UA_DeleteSubscriptionsResponse
UA_Client_Subscriptions_delete(UA_Client *client,
                               const UA_DeleteSubscriptionsRequest request) {
    lockClient(client);

    /* Send the request */
    UA_DeleteSubscriptionsResponse response;
    __Client_Service(client, &request,
                     &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
                     &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]);

    /* Process */
    __Client_Subscription_processDelete(client, &request, &response);

    unlockClient(client);
    return response;
}

UA_StatusCode
UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId) {
    UA_DeleteSubscriptionsRequest request;
    UA_DeleteSubscriptionsRequest_init(&request);
    request.subscriptionIds = &subscriptionId;
    request.subscriptionIdsSize = 1;

    UA_DeleteSubscriptionsResponse response =
        UA_Client_Subscriptions_delete(client, request);

    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteSubscriptionsResponse_clear(&response);
        return retval;
    }

    if(response.resultsSize != 1) {
        UA_DeleteSubscriptionsResponse_clear(&response);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    retval = response.results[0];
    UA_DeleteSubscriptionsResponse_clear(&response);
    return retval;
}

/******************/
/* MonitoredItems */
/******************/

static void
MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub,
                     UA_Client_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&client->clientMutex);

    ZIP_REMOVE(MonitorItemsTree, &sub->monitoredItems, mon);
    if(mon->deleteCallback)
        mon->deleteCallback(client, sub->subscriptionId, sub->context,
                            mon->monitoredItemId, mon->context);
    for(size_t i = 0; i < mon->eventFields.mapSize; i++) {
        UA_Variant_init(&mon->eventFields.map[i].value);
    }
    UA_KeyValueMap_clear(&mon->eventFields);
    UA_free(mon);
}

static UA_StatusCode
prepareEventFieldsMap(UA_Client_MonitoredItem *newMon,
                      UA_MonitoringParameters *params) {
    /* Get the EventFilter */
    UA_ExtensionObject *eo = &params->filter;
    if(eo->content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER])
        return UA_STATUSCODE_GOOD;
    UA_EventFilter *ef = (UA_EventFilter*)eo->content.decoded.data;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Check whether there are fields */
    if(ef->selectClausesSize == 0)
        return UA_STATUSCODE_GOOD;

    /* Allocate the map */
    newMon->eventFields.map = (UA_KeyValuePair*)
        UA_calloc(ef->selectClausesSize, sizeof(UA_KeyValuePair));
    if(!newMon->eventFields.map)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    newMon->eventFields.mapSize = ef->selectClausesSize;

    /* Create the key-strings for the fields */
    for(size_t i = 0; i < newMon->eventFields.mapSize; i++) {
        res |= UA_SimpleAttributeOperand_print(&ef->selectClauses[i],
                                               &newMon->eventFields.map[i].key.name);
    }

    return res;
}

static UA_StatusCode
MonitoredItem_createBegin(UA_Client *client, UA_Client_Subscription *sub,
                          UA_MonitoredItemCreateRequest *item,
                          UA_Client_DeleteMonitoredItemCallback deleteCallback,
                          void *context, void *handlingCallback,
                          UA_Client_MonitoredItem **outMon) {
    /* Allocate MonitoredItem */
    UA_Client_MonitoredItem *mon = (UA_Client_MonitoredItem *)
        UA_calloc(1, sizeof(UA_Client_MonitoredItem));
    if(!mon)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Cache the field name map */
    mon->isEventMonitoredItem =
        (item->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER);
    if(mon->isEventMonitoredItem) {
        UA_StatusCode res = prepareEventFieldsMap(mon, &item->requestedParameters);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free(mon);
            return res;
        }
    }

    /* Set a unique ClientHandle */
    item->requestedParameters.clientHandle = ++client->monitoredItemHandles;

    /* Fill in members and add to the client  */
    mon->clientHandle = item->requestedParameters.clientHandle;
    mon->context = context;
    mon->deleteCallback = deleteCallback;
    mon->handler.dataChangeCallback =
        (UA_Client_DataChangeNotificationCallback)(uintptr_t)handlingCallback;
    ZIP_INSERT(MonitorItemsTree, &sub->monitoredItems, mon);

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Subscription %" PRIu32 " | Added a MonitoredItem with handle %" PRIu32,
                 sub->subscriptionId, mon->clientHandle);

    *outMon = mon;
    return UA_STATUSCODE_GOOD;
}

static void
MonitoredItem_createFinish(UA_Client *client, UA_Client_Subscription *sub,
                           UA_Client_MonitoredItem *mon,
                           UA_MonitoredItemCreateResult *result) {
    UA_assert(result->statusCode == UA_STATUSCODE_GOOD);

    mon->monitoredItemId = result->monitoredItemId;
    /* revisedSamplingInterval; */
    /* revisedQueueSize; */
    /* filterResult; */
}

/************************************/
/* CreateMonitoredItems Synchronous */
/************************************/

static void
Client_MonitoredItems_create(UA_Client *client,
                             const UA_CreateMonitoredItemsRequest *constRequest,
                             void **contexts, void **handlingCallbacks,
                             UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                             UA_CreateMonitoredItemsResponse *response) {
    UA_LOCK_ASSERT(&client->clientMutex);
    UA_CreateMonitoredItemsResponse_init(response);

    /* Any items? */
    if(constRequest->itemsToCreateSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return;
    }

    /* Get the subscription */
    UA_Client_Subscription *sub =
        findSubscriptionById(client, constRequest->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Make a mutable copy. We modify the request to set the internal
     * clientHandle. */
    UA_CreateMonitoredItemsRequest request;
    UA_StatusCode res =
        UA_CreateMonitoredItemsRequest_copy(constRequest, &request);
    if(res != UA_STATUSCODE_GOOD) {
        response->responseHeader.serviceResult = res;
        return;
    }

    /* Create the MonitoredItems */
    UA_STACKARRAY(UA_Client_MonitoredItem*, mons, request.itemsToCreateSize);
    memset(mons, 0, sizeof(UA_Client_MonitoredItem*) * request.itemsToCreateSize);
    for(size_t i = 0; i < request.itemsToCreateSize; i++) {
        void *context = (contexts) ? contexts[i] : NULL;
        void *handlingCallback = (handlingCallbacks) ? handlingCallbacks[i] : NULL;
        UA_Client_DeleteMonitoredItemCallback deleteCallback =
            (deleteCallbacks) ? deleteCallbacks[i] : NULL;
        res |= MonitoredItem_createBegin(client, sub, &request.itemsToCreate[i],
                                         deleteCallback, context,
                                         handlingCallback, &mons[i]);
    }

    /* Failure -> Delete created MonitoredItems. Directly call deleteCallback if
     * creation failed. The MonitoredItemId is not yet known, use zero. */
    if(res != UA_STATUSCODE_GOOD) {
        for(size_t i = 0; i < request.itemsToCreateSize; i++) {
            if(mons[i])
                MonitoredItem_delete(client, sub, mons[i]);
            else if(deleteCallbacks && contexts)
                deleteCallbacks[i](client, request.subscriptionId,
                                   sub->context, 0, contexts[i]);
        }
        UA_CreateMonitoredItemsRequest_clear(&request);
        response->responseHeader.serviceResult = res;
        return;
    }

    /* Call the service */
    __Client_Service(client, &request,
                     &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
                     response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]);

    /* Check that the response size is good */
    if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
       response->resultsSize != request.itemsToCreateSize)
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;

    /* Update the MonitoredItems */
    for(size_t i = 0; i < request.itemsToCreateSize; i++) {
        UA_assert(mons[i]);
        UA_MonitoredItemCreateResult *item = &response->results[i];
        if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD ||
           item->statusCode != UA_STATUSCODE_GOOD) {
            MonitoredItem_delete(client, sub, mons[i]);
            continue;
        }
        MonitoredItem_createFinish(client, sub, mons[i], item);
    }

    UA_CreateMonitoredItemsRequest_clear(&request);
}

UA_CreateMonitoredItemsResponse
UA_Client_MonitoredItems_createDataChanges(UA_Client *client,
                                           const UA_CreateMonitoredItemsRequest request,
                                           void **contexts,
                                           UA_Client_DataChangeNotificationCallback *callbacks,
                                           UA_Client_DeleteMonitoredItemCallback *deleteCallbacks) {
    UA_CreateMonitoredItemsResponse response;
    lockClient(client);
    Client_MonitoredItems_create(client, &request, contexts, (void **)callbacks,
                                 deleteCallbacks, &response);
    unlockClient(client);
    return response;
}

UA_MonitoredItemCreateResult
UA_Client_MonitoredItems_createDataChange(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_TimestampsToReturn timestampsToReturn,
                                          const UA_MonitoredItemCreateRequest item,
                                          void *context,
                                          UA_Client_DataChangeNotificationCallback callback,
                                          UA_Client_DeleteMonitoredItemCallback deleteCallback) {
    UA_CreateMonitoredItemsRequest request;
    UA_CreateMonitoredItemsRequest_init(&request);
    request.subscriptionId = subscriptionId;
    request.timestampsToReturn = timestampsToReturn;
    request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item;
    request.itemsToCreateSize = 1;
    UA_CreateMonitoredItemsResponse response =
       UA_Client_MonitoredItems_createDataChanges(client, request, &context,
                                                   &callback, &deleteCallback);
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        result.statusCode = response.responseHeader.serviceResult;
    if(result.statusCode == UA_STATUSCODE_GOOD &&
       response.resultsSize != 1)
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
    if(result.statusCode == UA_STATUSCODE_GOOD) {
        result = response.results[0];
        UA_MonitoredItemCreateResult_init(&response.results[0]);
    }
    UA_CreateMonitoredItemsResponse_clear(&response);
    return result;
}

UA_CreateMonitoredItemsResponse
UA_Client_MonitoredItems_createEvents(UA_Client *client,
                                      const UA_CreateMonitoredItemsRequest request,
                                      void **contexts,
                                      UA_Client_EventNotificationCallback *callback,
                                      UA_Client_DeleteMonitoredItemCallback *deleteCallback) {
    UA_CreateMonitoredItemsResponse response;
    lockClient(client);
    Client_MonitoredItems_create(client, &request, contexts, (void **)callback,
                                 deleteCallback, &response);
    unlockClient(client);
    return response;
}

UA_MonitoredItemCreateResult
UA_Client_MonitoredItems_createEvent(UA_Client *client, UA_UInt32 subscriptionId,
                                     UA_TimestampsToReturn timestampsToReturn,
                                     const UA_MonitoredItemCreateRequest item, void *context,
                                     UA_Client_EventNotificationCallback callback,
                                     UA_Client_DeleteMonitoredItemCallback deleteCallback) {
    UA_CreateMonitoredItemsRequest request;
    UA_CreateMonitoredItemsRequest_init(&request);
    request.subscriptionId = subscriptionId;
    request.timestampsToReturn = timestampsToReturn;
    request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item;
    request.itemsToCreateSize = 1;
    UA_CreateMonitoredItemsResponse response =
       UA_Client_MonitoredItems_createEvents(client, request, &context,
                                             &callback, &deleteCallback);
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        result.statusCode = response.responseHeader.serviceResult;
    if(result.statusCode == UA_STATUSCODE_GOOD &&
       response.resultsSize != 1)
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
    if(result.statusCode == UA_STATUSCODE_GOOD) {
        result = response.results[0];
        UA_MonitoredItemCreateResult_init(&response.results[0]);
    }
    UA_CreateMonitoredItemsResponse_clear(&response);
    return result;
}

/*************************************/
/* CreateMonitoredItems Asynchronous */
/*************************************/

/* The handles are an array of [subId, monSize, monHandleId1, monHandle2, ...] */
static void
MonitoredItems_create_async_handler(UA_Client *client, void *data,
                                    UA_UInt32 requestId, void *resp) {
    CustomCallback *cc = (CustomCallback*)data;
    UA_UInt32 *handles = (UA_UInt32*)cc->clientData;
    UA_CreateMonitoredItemsResponse *response =
        (UA_CreateMonitoredItemsResponse *)resp;

    lockClient(client);

    /* Extract the first elements from the handles */
    UA_UInt32 subId = handles[0];
    UA_UInt32 monSize = handles[1];
    UA_UInt32 *monHandles = handles + 2;

    /* Check that the response size is good */
    if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
       response->resultsSize != monSize)
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;

    /* Get the Subscription from the SubscriptionId */
    UA_Client_Subscription *sub = findSubscriptionById(client, subId);
    if(!sub)
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;

    /* Update the MonitoredItems */
    UA_Client_MonitoredItem dummy;
    for(size_t i = 0; sub && i < monSize; i++) {
        /* Get the MonitoredItem from the ClientHandle */
        dummy.clientHandle = monHandles[i];
        UA_Client_MonitoredItem *mon =
            ZIP_FIND(MonitorItemsTree, &sub->monitoredItems, &dummy);
        if(!mon)
            continue;

        /* Delete MonitoredItem if the creation failed */
        UA_MonitoredItemCreateResult *item = &response->results[i];
        if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD ||
           item->statusCode != UA_STATUSCODE_GOOD) {
            MonitoredItem_delete(client, sub, mon);
            continue;
        }

        /* Update the MonitoredItem with the server's response  */
        MonitoredItem_createFinish(client, sub, mon, item);
    }

    /* Notify the application */
    if(cc->userCallback) {
        UA_ClientAsyncCreateMonitoredItemsCallback cb =
            (UA_ClientAsyncCreateMonitoredItemsCallback)cc->userCallback;
        cb(client, cc->userData, requestId, response);
    }

    /* Clean up */
    UA_free(handles);
    UA_free(cc);

    unlockClient(client);
}

static UA_StatusCode
Client_MonitoredItems_createAsync(UA_Client *client,
                                  const UA_CreateMonitoredItemsRequest *constRequest,
                                  void **contexts, void **handlingCallbacks,
                                  UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                                  UA_ClientAsyncServiceCallback createCallback,
                                  void *userdata, UA_UInt32 *requestId) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Get the Subscription */
    UA_Client_Subscription *sub =
        findSubscriptionById(client, constRequest->subscriptionId);
    if(!sub)
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;

    /* Any items? */
    if(constRequest->itemsToCreateSize == 0)
        return UA_STATUSCODE_BADNOTHINGTODO;

    /* Make a mutable copy. We modify the request to set the internal
     * clientHandle. */
    UA_CreateMonitoredItemsRequest request;
    UA_StatusCode res =
        UA_CreateMonitoredItemsRequest_copy(constRequest, &request);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Allocate context for the async handling */
    CustomCallback *cc = (CustomCallback*)UA_calloc(1, sizeof(CustomCallback));
    if(!cc) {
        UA_CreateMonitoredItemsRequest_clear(&request);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    UA_UInt32 *handles = (UA_UInt32*)
        UA_malloc(sizeof(UA_UInt32) * (request.itemsToCreateSize + 2));
    if(!handles) {
        UA_free(cc);
        UA_CreateMonitoredItemsRequest_clear(&request);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Create the MonitoredItems locally */
    UA_STACKARRAY(UA_Client_MonitoredItem*, mons, request.itemsToCreateSize);
    memset(mons, 0, sizeof(UA_Client_MonitoredItem*) * request.itemsToCreateSize);
    for(size_t i = 0; i < request.itemsToCreateSize; i++) {
        void *context = (contexts) ? contexts[i] : NULL;
        void *handlingCallback = (handlingCallbacks) ? handlingCallbacks[i] : NULL;
        UA_Client_DeleteMonitoredItemCallback deleteCallback =
            (deleteCallbacks) ? deleteCallbacks[i] : NULL;
        res |= MonitoredItem_createBegin(client, sub, &request.itemsToCreate[i],
                                         deleteCallback, context,
                                         handlingCallback, &mons[i]);
    }

    /* Failure -> Delete created MonitoredItems. Directly call deleteCallback if
     * creation failed. The MonitoredItemId is not yet known, use zero. */
    if(res != UA_STATUSCODE_GOOD) {
        for(size_t i = 0; i < request.itemsToCreateSize; i++) {
            if(mons[i])
                MonitoredItem_delete(client, sub, mons[i]);
            else if(deleteCallbacks && contexts)
                deleteCallbacks[i](client, request.subscriptionId,
                                   sub->context, 0, contexts[i]);
        }
        UA_free(handles);
        UA_free(cc);
        UA_CreateMonitoredItemsRequest_clear(&request);
        return res;
    }

    /* Set the async handler context */
    handles[0] = sub->subscriptionId;
    handles[1] = (UA_UInt32)request.itemsToCreateSize;
    for(size_t i = 0; i < request.itemsToCreateSize; i++) {
        handles[i+2] = mons[i]->clientHandle;
    }
    cc->clientData = handles;
    cc->userCallback = createCallback;
    cc->userData = userdata;

    /* Call the service asynchronously */
    res = __Client_AsyncService(client, &request,
                                &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
                                MonitoredItems_create_async_handler,
                                &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE],
                                cc, requestId);

    /* Manually clean up the context in the failure case */
    if(res != UA_STATUSCODE_GOOD) {
        for(size_t i = 0; i < request.itemsToCreateSize; i++) {
            UA_assert(mons[i]);
            MonitoredItem_delete(client, sub, mons[i]);
        }
        UA_free(handles);
        UA_free(cc);
    }

    /* Clean up */
    UA_CreateMonitoredItemsRequest_clear(&request);
    return res;
}

UA_StatusCode
UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client,
                                                 const UA_CreateMonitoredItemsRequest request,
                                                 void **contexts,
                                                 UA_Client_DataChangeNotificationCallback *callbacks,
                                                 UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                                                 UA_ClientAsyncCreateMonitoredItemsCallback createCallback,
                                                 void *userdata, UA_UInt32 *requestId) {
    lockClient(client);
    UA_StatusCode res =
        Client_MonitoredItems_createAsync(client, &request, contexts,
                                          (void **)callbacks, deleteCallbacks,
                                          (UA_ClientAsyncServiceCallback)createCallback,
                                          userdata, requestId);
    unlockClient(client);
    return res;
}

UA_StatusCode
UA_Client_MonitoredItems_createEvents_async(UA_Client *client,
                                            const UA_CreateMonitoredItemsRequest request,
                                            void **contexts,
                                            UA_Client_EventNotificationCallback *callbacks,
                                            UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                                            UA_ClientAsyncCreateMonitoredItemsCallback createCallback,
                                            void *userdata, UA_UInt32 *requestId) {
    lockClient(client);
    UA_StatusCode res =
        Client_MonitoredItems_createAsync(client, &request, contexts,
                                          (void **)callbacks, deleteCallbacks,
                                          (UA_ClientAsyncServiceCallback)createCallback,
                                          userdata, requestId);
    unlockClient(client);
    return res;
}

static void
MonitoredItems_delete(UA_Client *client, UA_Client_Subscription *sub,
                      const UA_DeleteMonitoredItemsRequest *request,
                      const UA_DeleteMonitoredItemsResponse *response) {
#ifdef __clang_analyzer__
    return;
#endif

    /* Loop over deleted MonitoredItems */
    struct UA_Client_MonitoredItem_ForDelete deleteMonitoredItem;
    memset(&deleteMonitoredItem, 0, sizeof(struct UA_Client_MonitoredItem_ForDelete));
    deleteMonitoredItem.client = client;
    deleteMonitoredItem.sub = sub;

    for(size_t i = 0; i < response->resultsSize; i++) {
        if(response->results[i] != UA_STATUSCODE_GOOD &&
           response->results[i] != UA_STATUSCODE_BADMONITOREDITEMIDINVALID) {
            continue;
        }
        deleteMonitoredItem.monitoredItemId = &request->monitoredItemIds[i];
        /* Delete the internal representation */
        ZIP_ITER(MonitorItemsTree,&sub->monitoredItems,
                 MonitoredItem_delete_wrapper, &deleteMonitoredItem);
    }
}

static void
MonitoredItems_delete_handler(UA_Client *client, void *d, UA_UInt32 requestId, void *r) {
    UA_Client_Subscription *sub = NULL;
    CustomCallback *cc = (CustomCallback *)d;
    UA_DeleteMonitoredItemsResponse *response = (UA_DeleteMonitoredItemsResponse *)r;
    UA_DeleteMonitoredItemsRequest *request =
        (UA_DeleteMonitoredItemsRequest *)cc->clientData;

    lockClient(client);

    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        goto cleanup;

    sub = findSubscriptionById(client, request->subscriptionId);
    if(!sub) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "No internal representation of subscription %" PRIu32,
                    request->subscriptionId);
        goto cleanup;
    }

    /* Delete MonitoredItems from the internal representation */
    MonitoredItems_delete(client, sub, request, response);

cleanup:
    if(cc->userCallback)
        cc->userCallback(client, cc->userData, requestId, response);
    UA_DeleteMonitoredItemsRequest_delete(request);
    UA_free(cc);

    unlockClient(client);
}

UA_DeleteMonitoredItemsResponse
UA_Client_MonitoredItems_delete(UA_Client *client,
                                const UA_DeleteMonitoredItemsRequest request) {
    /* Send the request */
    UA_DeleteMonitoredItemsResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
                        &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]);

    /* A problem occured remote? */
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return response;

    lockClient(client);

    /* Find the internal subscription representation */
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
    if(!sub) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "No internal representation of subscription %" PRIu32,
                    request.subscriptionId);
        unlockClient(client);
        return response;
    }

    /* Remove MonitoredItems in the internal representation */
    MonitoredItems_delete(client, sub, &request, &response);

    unlockClient(client);

    return response;
}

UA_StatusCode
UA_Client_MonitoredItems_delete_async(UA_Client *client,
                                      const UA_DeleteMonitoredItemsRequest request,
                                      UA_ClientAsyncDeleteMonitoredItemsCallback callback,
                                      void *userdata, UA_UInt32 *requestId) {
    /* Send the request */
    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
    if(!cc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_DeleteMonitoredItemsRequest *req_copy = UA_DeleteMonitoredItemsRequest_new();
    if(!req_copy) {
        UA_free(cc);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_DeleteMonitoredItemsRequest_copy(&request, req_copy);
    cc->clientData = req_copy;
    cc->userCallback = (UA_ClientAsyncServiceCallback)callback;
    cc->userData = userdata;

    UA_StatusCode res =
        __UA_Client_AsyncService(client, &request,
                                 &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
                                 MonitoredItems_delete_handler,
                                 &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE],
                                 cc, requestId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_DeleteMonitoredItemsRequest_delete(req_copy);
        UA_free(cc);
    }
    return res;
}

UA_StatusCode
UA_Client_MonitoredItems_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId,
                                      UA_UInt32 monitoredItemId) {
    UA_DeleteMonitoredItemsRequest request;
    UA_DeleteMonitoredItemsRequest_init(&request);
    request.subscriptionId = subscriptionId;
    request.monitoredItemIds = &monitoredItemId;
    request.monitoredItemIdsSize = 1;

    UA_DeleteMonitoredItemsResponse response =
        UA_Client_MonitoredItems_delete(client, request);

    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteMonitoredItemsResponse_clear(&response);
        return retval;
    }

    if(response.resultsSize != 1) {
        UA_DeleteMonitoredItemsResponse_clear(&response);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    retval = response.results[0];
    UA_DeleteMonitoredItemsResponse_clear(&response);
    return retval;
}

static void *
MonitoredItem_findByID(void *data, UA_Client_MonitoredItem *mon) {
    UA_UInt32 monitorId = *(UA_UInt32*)data;
    if(monitorId && (mon->monitoredItemId == monitorId))
        return mon;
    return NULL;
}

static UA_Client_MonitoredItem *
findMonitoredItemById(UA_Client_Subscription *sub, UA_UInt32 monitoredItemId) {
    return (UA_Client_MonitoredItem *)
        ZIP_ITER(MonitorItemsTree, &sub->monitoredItems,
                 MonitoredItem_findByID, &monitoredItemId);
}

static void
setExistingClientHandles(UA_Client_Subscription *sub,
                         UA_ModifyMonitoredItemsRequest *request) {
    for(size_t i = 0; i < request->itemsToModifySize; ++i) {
        UA_MonitoredItemModifyRequest *mimr = &request->itemsToModify[i];
        UA_Client_MonitoredItem *mon =
            findMonitoredItemById(sub, mimr->monitoredItemId);
        if(mon)
            mimr->requestedParameters.clientHandle = mon->clientHandle;
    }
}

UA_ModifyMonitoredItemsResponse
UA_Client_MonitoredItems_modify(UA_Client *client,
                                const UA_ModifyMonitoredItemsRequest request) {
    UA_ModifyMonitoredItemsResponse response;
    UA_ModifyMonitoredItemsResponse_init(&response);

    /* Make a modifiable copy of the request */
    UA_ModifyMonitoredItemsRequest modifiedRequest;
    UA_StatusCode res = UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest);
    if(res != UA_STATUSCODE_GOOD) {
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return response;
    }

    lockClient(client);

    /* Get the subscription */
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
    if(!sub) {
        unlockClient(client);
        UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return response;
    }

    /* Reuse the existing ClientHandles for the MonitoredItems */
    setExistingClientHandles(sub, &modifiedRequest);

    /* Call the service */
    __Client_Service(client, &modifiedRequest,
                     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], &response,
                     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]);

    unlockClient(client);

    /* Clean up */
    UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
    return response;
}

UA_StatusCode
UA_Client_MonitoredItems_modify_async(UA_Client *client,
                                      const UA_ModifyMonitoredItemsRequest request,
                                      UA_ClientAsyncModifyMonitoredItemsCallback callback,
                                      void *userdata, UA_UInt32 *requestId) {
    /* Make a modifiable copy of the request */
    UA_ModifyMonitoredItemsRequest modifiedRequest;
    UA_StatusCode res = UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    lockClient(client);

    /* Get the subscription */
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
    if(!sub) {
        unlockClient(client);
        UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* Reuse the existing ClientHandles for the MonitoredItems */
    setExistingClientHandles(sub, &modifiedRequest);

    /* Call the service */
    UA_StatusCode statusCode = __Client_AsyncService(
        client, &modifiedRequest, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST],
        (UA_ClientAsyncServiceCallback)callback,
        &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE], userdata, requestId);

    unlockClient(client);

    /* Clean up */
    UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
    return statusCode;
}

UA_StatusCode
UA_Client_MonitoredItem_getContext(UA_Client *client, UA_UInt32 subscriptionId,
                                   UA_UInt32 monitoredItemId, void **monContext) {
    if(!client || !monContext)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    *monContext = NULL;

    lockClient(client);
    UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
    if(!sub) {
        unlockClient(client);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    UA_StatusCode itemstatus = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    UA_Client_MonitoredItem *monItem = findMonitoredItemById(sub, monitoredItemId);
    if(monItem) {
        *monContext = monItem->context;
        itemstatus = UA_STATUSCODE_GOOD;
    }
    unlockClient(client);
    return itemstatus;
}

UA_StatusCode
UA_Client_MonitoredItem_setContext(UA_Client *client, UA_UInt32 subscriptionId,
                                   UA_UInt32 monitoredItemId, void *monContext) {
    if(!client)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockClient(client);
    UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
    if(!sub) {
        unlockClient(client);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    UA_StatusCode itemstatus = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    UA_Client_MonitoredItem *monItem = findMonitoredItemById(sub, monitoredItemId);
    if(monItem) {
        monItem->context = monContext;
        itemstatus = UA_STATUSCODE_GOOD;
    }
    unlockClient(client);
    return itemstatus;
}

/*************************************/
/* Async Processing of Notifications */
/*************************************/

/* Assume the request is already initialized */
UA_StatusCode
__Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Count acks */
    UA_Client_NotificationsAckNumber *ack;
    LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
        ++request->subscriptionAcknowledgementsSize;

    /* Create the array. Returns a sentinel pointer if the length is zero. */
    request->subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement*)
        UA_Array_new(request->subscriptionAcknowledgementsSize,
                     &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT]);
    if(!request->subscriptionAcknowledgements) {
        request->subscriptionAcknowledgementsSize = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    size_t i = 0;
    UA_Client_NotificationsAckNumber *ack_tmp;
    LIST_FOREACH_SAFE(ack, &client->pendingNotificationsAcks, listEntry, ack_tmp) {
        LIST_REMOVE(ack, listEntry);
        UA_SubscriptionAcknowledgement *reqAck = &request->subscriptionAcknowledgements[i];
        reqAck->sequenceNumber = ack->subAck.sequenceNumber;
        reqAck->subscriptionId = ack->subAck.subscriptionId;
        UA_free(ack);
        i++;
    }
    return UA_STATUSCODE_GOOD;
}

/* According to specification, Part 4 5.13.1, the value 0 is never used for the
 * sequence number */
static UA_UInt32
__nextSequenceNumber(UA_UInt32 sequenceNumber) {
    UA_UInt32 nextSequenceNumber = sequenceNumber + 1;
    if(nextSequenceNumber == 0)
        nextSequenceNumber = 1;
    return nextSequenceNumber;
}

static void
processDataChangeNotification(UA_Client *client, UA_Client_Subscription *sub,
                              UA_DataChangeNotification *dataChangeNotification) {
    UA_LOCK_ASSERT(&client->clientMutex);

    for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) {
        UA_MonitoredItemNotification *min = &dataChangeNotification->monitoredItems[j];

        /* Find the MonitoredItem */
        UA_Client_MonitoredItem *mon;
        UA_Client_MonitoredItem dummy;
        dummy.clientHandle = min->clientHandle;
        mon = ZIP_FIND(MonitorItemsTree, &sub->monitoredItems, &dummy);

        if(!mon) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Could not process a notification with clienthandle %" PRIu32
                           " on subscription %" PRIu32, min->clientHandle, sub->subscriptionId);
            continue;
        }

        if(mon->isEventMonitoredItem) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "MonitoredItem is configured for Events. But received a "
                           "DataChangeNotification.");
            continue;
        }

        if(mon->handler.dataChangeCallback) {
            void *subC = sub->context;
            void *monC = mon->context;
            UA_UInt32 subId = sub->subscriptionId;
            UA_UInt32 monId = mon->monitoredItemId;
            mon->handler.dataChangeCallback(client, subId, subC, monId, monC, &min->value);
        }
    }
}

static void
processEventNotification(UA_Client *client, UA_Client_Subscription *sub,
                         UA_EventNotificationList *eventNotificationList) {
    UA_LOCK_ASSERT(&client->clientMutex);

    for(size_t j = 0; j < eventNotificationList->eventsSize; ++j) {
        UA_EventFieldList *efl = &eventNotificationList->events[j];

        /* Find the MonitoredItem */
        UA_Client_MonitoredItem *mon;
        UA_Client_MonitoredItem dummy;
        dummy.clientHandle = efl->clientHandle;
        mon = ZIP_FIND(MonitorItemsTree, &sub->monitoredItems, &dummy);

        if(!mon) {
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Could not process a notification with clienthandle %" PRIu32
                         " on subscription %" PRIu32, efl->clientHandle,
                         sub->subscriptionId);
            continue;
        }

        if(!mon->isEventMonitoredItem) {
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "MonitoredItem is configured for DataChanges. But received a "
                         "EventNotification");
            continue;
        }

        if(mon->eventFields.mapSize != efl->eventFieldsSize) {
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "MonitoredItem received a EventNotification with the "
                          "wrong number of event fields");
            continue;
        }

        /* Prepare the key-value map and call the callback  */
        for(size_t i = 0; i < mon->eventFields.mapSize; i++) {
            mon->eventFields.map[i].value = efl->eventFields[i];
        }
        mon->handler.eventCallback(client, sub->subscriptionId, sub->context,
                                   mon->monitoredItemId, mon->context, mon->eventFields);
    }
}

static void
processNotificationMessage(UA_Client *client, UA_Client_Subscription *sub,
                           UA_ExtensionObject *msg) {
    UA_LOCK_ASSERT(&client->clientMutex);

    if(msg->encoding != UA_EXTENSIONOBJECT_DECODED)
        return;

    /* Handle DataChangeNotification */
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
        UA_DataChangeNotification *dataChangeNotification =
            (UA_DataChangeNotification *)msg->content.decoded.data;
        processDataChangeNotification(client, sub, dataChangeNotification);
        return;
    }

    /* Handle EventNotification */
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]) {
        UA_EventNotificationList *eventNotificationList =
            (UA_EventNotificationList *)msg->content.decoded.data;
        processEventNotification(client, sub, eventNotificationList);
        return;
    }

    /* Handle StatusChangeNotification */
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]) {
        if(sub->statusChangeCallback) {
            void *subC = sub->context;
            UA_UInt32 subId = sub->subscriptionId;
            sub->statusChangeCallback(client, subId, subC,
                                      (UA_StatusChangeNotification*)msg->content.decoded.data);
        } else {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Dropped a StatusChangeNotification since no "
                           "callback is registered");
        }
        return;
    }

    UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                   "Unknown notification message type");
}

static void
__Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
                                              UA_PublishResponse *response) {
    UA_LOCK_ASSERT(&client->clientMutex);

    /* Reduce the number of "in-flight" PublishRequests */
    client->currentlyOutStandingPublishRequests--;

    /* Process ServiceResult for bad StatusCodes without referring to a
     * SubscriptionId */
    switch(response->responseHeader.serviceResult) {
    case UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS:
        /* Correct the assumed number of max outstanding requests */
        if(client->config.outStandingPublishRequests > 1) {
            client->config.outStandingPublishRequests--;
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "PublishResponse: Too many PublishRequest, reduce "
                           "outStandingPublishRequests to %" PRId16,
                           client->config.outStandingPublishRequests);
        } else {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "PublishResponse: Too many PublishRequests when "
                         "outStandingPublishRequests = 1");
            UA_Client_Subscriptions_deleteSingle(client, response->subscriptionId);
        }
        return;

    case UA_STATUSCODE_BADSHUTDOWN:
        /* If the remote server shuts down, DEBUG-log to avoid a warning-storm
         * for normal operations */
        UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "PublishResponse: Received BadShutdown status");
        return;

    case UA_STATUSCODE_BADNOSUBSCRIPTION:
        /* There is no Subscription configured, the server expects no
         * PublishRequests. We demote this to debug-logging, as it can occur
         * during regular shutdown when the Subscriptions are removed. */
        UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "PublishResponse: Received BadNoSubscription status");
        return;

    default:
        break;
    }

    /* Get the Subscription */
    UA_Client_Subscription *sub = findSubscriptionById(client, response->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION;
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "PublishResponse: Received response for an unknown Subscription");
        return;
    }

    /* Process ServiceResult */
    switch(response->responseHeader.serviceResult) {
    case UA_STATUSCODE_BADSESSIONCLOSED:
        /* The Session no longer exists on the server - remove the Subscription */
        __Client_Subscription_deleteInternal(client, sub);
        return;

    case UA_STATUSCODE_BADTIMEOUT:
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "PublishResponse: Aborted with BadTimeout status");
        if(client->config.subscriptionInactivityCallback) {
            void *subC = sub->context;
            UA_UInt32 subId = sub->subscriptionId;
            client->config.subscriptionInactivityCallback(client, subId, subC);
        }
        return;

    case UA_STATUSCODE_GOOD:
        break; /* Continue below */

    default:
        /* Catch-all for other bad StatusCodes */
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "PublishResponse: Received %s status",
                       UA_StatusCode_name(response->responseHeader.serviceResult));
        return;
    }

    /* Update the LastActivity for the Subscription */
    UA_EventLoop *el = client->config.eventLoop;
    sub->lastActivity = el->dateTime_nowMonotonic(el);

    /* Detect missing message - OPC Unified Architecture, Part 4 5.13.1.1 e) */
    UA_NotificationMessage *msg = &response->notificationMessage;
    if(__nextSequenceNumber(sub->sequenceNumber) != msg->sequenceNumber) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "PublishResponse: Invalid subscription sequence number: "
                       "Expected %" PRIu32 " but got %" PRIu32,
                       __nextSequenceNumber(sub->sequenceNumber), msg->sequenceNumber);
        /* This is an error. But we do not abort the connection. Some server
         * SDKs misbehave from time to time and send out-of-order sequence
         * numbers. (Probably some multi-threading synchronization issue.) */
        /* UA_Client_disconnect(client);
           return; */
    }

    /* According to f), a keep-alive message contains no notifications and has
     * the sequence number of the next NotificationMessage that is to be sent =>
     * More than one consecutive keep-alive message or a NotificationMessage
     * following a keep-alive message will share the same sequence number. */
    if(msg->notificationDataSize)
        sub->sequenceNumber = msg->sequenceNumber;

    /* Process the notification messages */
    for(size_t k = 0; k < msg->notificationDataSize; ++k)
        processNotificationMessage(client, sub, &msg->notificationData[k]);

    /* Add the current NotificationMessage (SequenceNumber) to the list of
     * pending acks to be acknowledged. But only if it is in the list of
     * sequence numbers the server has available. */
    for(size_t i = 0; i < response->availableSequenceNumbersSize; i++) {
        if(response->availableSequenceNumbers[i] != msg->sequenceNumber)
            continue;
        UA_Client_NotificationsAckNumber *tmpAck = (UA_Client_NotificationsAckNumber*)
            UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
        if(!tmpAck) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "PublishResponse: Not enough memory to store the pending "
                           "acknowledgement for Subscription %" PRIu32, sub->subscriptionId);
            break;
        }
        tmpAck->subAck.sequenceNumber = msg->sequenceNumber;
        tmpAck->subAck.subscriptionId = sub->subscriptionId;
        LIST_INSERT_HEAD(&client->pendingNotificationsAcks, tmpAck, listEntry);
        break;
    }
}

static void
processPublishResponseAsync(UA_Client *client, void *userdata,
                            UA_UInt32 requestId, void *response) {
    UA_PublishRequest *req = (UA_PublishRequest*)userdata;
    UA_PublishResponse *res = (UA_PublishResponse*)response;

    lockClient(client);

    /* Process the response */
    __Client_Subscriptions_processPublishResponse(client, req, res);

    /* Delete the cached request */
    UA_PublishRequest_delete(req);

    /* Fill up the outstanding publish requests */
    __Client_Subscriptions_backgroundPublish(client);

    unlockClient(client);
}

void
__Client_Subscriptions_clear(UA_Client *client) {
    UA_Client_NotificationsAckNumber *n;
    UA_Client_NotificationsAckNumber *tmp;
    LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) {
        LIST_REMOVE(n, listEntry);
        UA_free(n);
    }

    UA_Client_Subscription *sub;
    UA_Client_Subscription *tmps;
    LIST_FOREACH_SAFE(sub, &client->subscriptions, listEntry, tmps)
        __Client_Subscription_deleteInternal(client, sub); /* force local removal */

    client->monitoredItemHandles = 0;
}

void
__Client_Subscriptions_backgroundPublishInactivityCheck(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime nowm = el->dateTime_nowMonotonic(el);

    UA_Client_Subscription *sub;
    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
        UA_DateTime maxSilence = (UA_DateTime)
            ((sub->publishingInterval * sub->maxKeepAliveCount) +
             client->config.timeout) * UA_DATETIME_MSEC;
        if(maxSilence + sub->lastActivity < nowm) {
            /* Reset activity */
            sub->lastActivity = nowm;

            if(client->config.subscriptionInactivityCallback) {
                void *subC = sub->context;
                UA_UInt32 subId = sub->subscriptionId;
                client->config.subscriptionInactivityCallback(client, subId, subC);
            }
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Inactivity for Subscription %" PRIu32 ".",
                           sub->subscriptionId);
        }
    }
}

void
__Client_Subscriptions_backgroundPublish(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex);

    if(client->sessionState != UA_SESSIONSTATE_ACTIVATED)
        return;

    /* The session must have at least one subscription */
    if(!LIST_FIRST(&client->subscriptions))
        return;

    while(client->currentlyOutStandingPublishRequests < client->config.outStandingPublishRequests) {
        UA_PublishRequest *request = UA_PublishRequest_new();
        if(!request)
            return;

        /* Publish requests are valid for 10 minutes */
        request->requestHeader.timeoutHint = 10 * 60 * 1000;

        UA_StatusCode retval = __Client_preparePublishRequest(client, request);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_PublishRequest_delete(request);
            return;
        }

        retval = __Client_AsyncService(client, request,
                                         &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
                                         processPublishResponseAsync,
                                         &UA_TYPES[UA_TYPES_PUBLISHRESPONSE],
                                         (void*)request, NULL);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_PublishRequest_delete(request);
            return;
        }

        client->currentlyOutStandingPublishRequests++;
    }
}

UA_SetPublishingModeResponse
UA_Client_Subscriptions_setPublishingMode(UA_Client *client,
                                          const UA_SetPublishingModeRequest request) {
    UA_SetPublishingModeResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST],
                        &response, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]);
    return response;
}

UA_SetMonitoringModeResponse
UA_Client_MonitoredItems_setMonitoringMode(UA_Client *client,
                                           const UA_SetMonitoringModeRequest request) {
    UA_SetMonitoringModeResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST],
                        &response, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]);
    return response;
}

UA_StatusCode
UA_Client_MonitoredItems_setMonitoringMode_async(UA_Client *client,
                                                 const UA_SetMonitoringModeRequest request,
                                                 UA_ClientAsyncSetMonitoringModeCallback callback,
                                                 void *userdata, UA_UInt32 *requestId) {
    return __UA_Client_AsyncService(client, &request,
                                    &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST],
                                    (UA_ClientAsyncServiceCallback)callback,
                                    &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE],
                                    userdata, requestId);
}

UA_SetTriggeringResponse
UA_Client_MonitoredItems_setTriggering(UA_Client *client,
                                       const UA_SetTriggeringRequest request) {
    UA_SetTriggeringResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST],
                        &response, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]);
    return response;
}

UA_StatusCode
UA_Client_MonitoredItems_setTriggering_async(UA_Client *client,
                                             const UA_SetTriggeringRequest request,
                                             UA_ClientAsyncSetTriggeringCallback callback,
                                             void *userdata, UA_UInt32 *requestId) {
    return __UA_Client_AsyncService(client, &request,
                                    &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST],
                                    (UA_ClientAsyncServiceCallback)callback,
                                    &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE],
                                    userdata, requestId);
}

/**** amalgamated original file "/src/client/ua_client_util.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2025 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


typedef struct NodeIdTreeEntry {
    ZIP_ENTRY(NodeIdTreeEntry) zipfields;
    UA_NodeId nodeId;
    UA_String typeName;
} NodeIdTreeEntry;

static enum ZIP_CMP
cmpNodeIdTreeEntry(const void *a, const void *b) {
    const UA_NodeId *aa = (const UA_NodeId*)a;
    const UA_NodeId *bb = (const UA_NodeId*)b;
    return (enum ZIP_CMP)UA_NodeId_order(aa, bb);
}

typedef ZIP_HEAD(NodeIdTree, NodeIdTreeEntry) NodeIdTree;
ZIP_FUNCTIONS(NodeIdTree, NodeIdTreeEntry, zipfields,
              UA_NodeId, nodeId, cmpNodeIdTreeEntry)

static void *
deleteNodeIdEntry(void *context, NodeIdTreeEntry *elm) {
    UA_NodeId_clear(&elm->nodeId);
    UA_String_clear(&elm->typeName);
    UA_free(elm);
    return NULL;
}

static UA_StatusCode
browseDataTypesRecursive(UA_Client *client, NodeIdTree *tree,
                         size_t *treeSize, UA_NodeId typeNode) {
    /* Set up the browse request */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = typeNode;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
    bd.referenceTypeId = UA_NS0ID(HASSUBTYPE);
    bd.nodeClassMask = UA_NODECLASS_DATATYPE;

    /* Browse */
    UA_BrowseResult br = UA_Client_browse(client, NULL, 0, &bd);
    UA_StatusCode res = br.statusCode;
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Could not browse the DataTypeNodes with status code %s",
                     UA_StatusCode_name(res));
        UA_BrowseResult_clear(&br);
        return res;
    }

    /* Check which types are unknown, add them and recurse */
    for(size_t i = 0; i < br.referencesSize && res == UA_STATUSCODE_GOOD; i++) {
        UA_ReferenceDescription *rd = &br.references[i];
        if(!UA_ExpandedNodeId_isLocal(&rd->nodeId))
            continue;

        /* Skip known types */
        if(UA_findDataTypeWithCustom(&rd->nodeId.nodeId,
                                     client->config.customDataTypes))
            continue;
        if(ZIP_FIND(NodeIdTree, tree, &rd->nodeId.nodeId))
            continue;

        /* Create an entry */
        NodeIdTreeEntry *entry = (NodeIdTreeEntry*)UA_malloc(sizeof(NodeIdTreeEntry));
        if(!entry) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
            break;
        }
        *entry = (NodeIdTreeEntry){{NULL, NULL}, rd->nodeId.nodeId, rd->displayName.text};
            
        ZIP_INSERT(NodeIdTree, tree, entry);
        (*treeSize)++;

        /* Recurse */
        res = browseDataTypesRecursive(client, tree, treeSize, rd->nodeId.nodeId);

        /* Don't double-free */
        UA_NodeId_init(&rd->nodeId.nodeId);
        UA_String_init(&rd->displayName.text);
    }

    UA_BrowseResult_clear(&br);
    return res;
}

static UA_StatusCode
getRemoteDataTypes(UA_Client *client, UA_ReadRequest *req,
                   UA_DataTypeArray **outCustomTypes) {
    UA_ReadResponse rr = UA_Client_Service_read(client, *req);
    UA_StatusCode res = rr.responseHeader.serviceResult;
    if(res == UA_STATUSCODE_GOOD && rr.resultsSize != req->nodesToReadSize)
        res = UA_STATUSCODE_BADINTERNALERROR;
    if(res != UA_STATUSCODE_GOOD) {
        UA_ReadResponse_clear(&rr);
        return res;
    }

    /* Allocate the arrays */
    size_t typesSize = req->nodesToReadSize / 2;
    UA_DataTypeArray *dta = (UA_DataTypeArray*)
        UA_calloc(1, sizeof(UA_DataTypeArray));
    if(!dta) {
        UA_ReadResponse_clear(&rr);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    dta->cleanup = true;
    dta->types = (UA_DataType*)UA_calloc(typesSize, sizeof(UA_DataType));
    if(!dta->types) {
        UA_ReadResponse_clear(&rr);
        UA_cleanupDataTypeWithCustom(dta);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Create the new types */
    for(size_t i = 0; i < typesSize; i++) {
        UA_DataValue *typeDef = &rr.results[i];
        if(typeDef->hasStatus && typeDef->status != UA_STATUSCODE_GOOD)
            continue;
        if(!typeDef->hasValue || !UA_Variant_hasScalarType(&typeDef->value,
                                                           &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]))
            continue;
        UA_StructureDefinition *sd = (UA_StructureDefinition*)typeDef->value.data;

        UA_DataValue *typeName = &rr.results[i+typesSize];
        if(typeName->hasStatus && typeName->status != UA_STATUSCODE_GOOD)
            continue;
        if(!typeName->hasValue || !UA_Variant_hasScalarType(&typeName->value,
                                                            &UA_TYPES[UA_TYPES_QUALIFIEDNAME]))
            continue;

        UA_StructureDescription descr;
        descr.structureDefinition = *sd;
        descr.dataTypeId = req->nodesToRead[i].nodeId;
        descr.name = *(UA_QualifiedName*)typeName->value.data;
        UA_ExtensionObject eo;
        UA_ExtensionObject_setValue(&eo, &descr, &UA_TYPES[UA_TYPES_STRUCTUREDESCRIPTION]);

        UA_DataTypeArray lookupTypes = *dta;
        lookupTypes.next = client->config.customDataTypes;

        res = UA_DataType_fromDescription(&dta->types[dta->typesSize], &eo,
                                          &lookupTypes);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Could not add the DataType %Q (%N) with status code %s",
                         descr.name, req->nodesToRead[i].nodeId, UA_StatusCode_name(res));
            continue;
        }

        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Added DataType %Q (%N) to the DataTypeArray",
                    descr.name, req->nodesToRead[i].nodeId);
        dta->typesSize++;
    }

    *outCustomTypes = dta;

    UA_ReadResponse_clear(&rr);
    UA_ReadRequest_clear(req);
    if(dta->typesSize == 0) {
        UA_free(dta->types);
        dta->types = NULL;
    }
    return UA_STATUSCODE_GOOD;
}

static void *
setNodesToRead(void *context, NodeIdTreeEntry *elm) {
    UA_ReadValueId **rvi = (UA_ReadValueId**)context;
    (*rvi)->nodeId = elm->nodeId;
    (*rvi)->attributeId = UA_ATTRIBUTEID_DATATYPEDEFINITION;
    (*rvi)++;
    UA_free(elm);
    return NULL;
}

UA_StatusCode UA_EXPORT UA_THREADSAFE
UA_Client_getRemoteDataTypes(UA_Client *client,
                             size_t dataTypesNodesSize,
                             const UA_NodeId *dataTypesNodes,
                             UA_DataTypeArray **customTypes) {
    if(!customTypes)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_ReadRequest req;
    UA_ReadRequest_init(&req);

    /* req.nodesToRead has twice the normal length. Because we read the
     * DataTypeDescription and the DisplayName in the same request. */

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(dataTypesNodesSize == 0) {
        /* Browse to find unknown datatypes in the information model */

        /* Get all unknown DataType NodeIds */
        NodeIdTree tree;
        ZIP_INIT(&tree);
        size_t treeSize = 0;
        res = browseDataTypesRecursive(client, &tree, &treeSize, UA_NS0ID(STRUCTURE));
        if(res != UA_STATUSCODE_GOOD) {
            ZIP_ITER(NodeIdTree, &tree, deleteNodeIdEntry, NULL);
            return res;
        }

        if(treeSize == 0)
            return UA_STATUSCODE_GOOD;

        /* Read the descriptions of the unknown types */
        UA_ReadValueId *nodesToRead = (UA_ReadValueId*)
            UA_calloc(treeSize * 2, sizeof(UA_ReadValueId));
        if(!nodesToRead) {
            ZIP_ITER(NodeIdTree, &tree, deleteNodeIdEntry, NULL);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        UA_ReadValueId *tmp = nodesToRead;
        ZIP_ITER(NodeIdTree, &tree, setNodesToRead, &tmp);
        req.nodesToRead = nodesToRead;
        req.nodesToReadSize = treeSize;
    } else {
        /* Prepare the ReadRequest for the provided NodeIds */
        req.nodesToRead = (UA_ReadValueId*)
            UA_Array_new(dataTypesNodesSize * 2, &UA_TYPES[UA_TYPES_READVALUEID]);
        if(!req.nodesToRead)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        req.nodesToReadSize = dataTypesNodesSize;

        for(size_t i = 0; i < dataTypesNodesSize; i++) {
            req.nodesToRead[i].attributeId = UA_ATTRIBUTEID_DATATYPEDEFINITION;
            res |= UA_NodeId_copy(&dataTypesNodes[i], &req.nodesToRead[i].nodeId);
        }

        if(res != UA_STATUSCODE_GOOD) {
            UA_ReadRequest_clear(&req);
            return res;
        }
    }

    /* Prepare reading the BrowseName attributes additionally */
    for(size_t i = 0; i < req.nodesToReadSize; i++) {
        res |= UA_NodeId_copy(&req.nodesToRead[i].nodeId,
                              &req.nodesToRead[i + req.nodesToReadSize].nodeId);
        req.nodesToRead[i + req.nodesToReadSize].attributeId = UA_ATTRIBUTEID_BROWSENAME;
    }
    req.nodesToReadSize *= 2;
    if(res != UA_STATUSCODE_GOOD) {
        UA_ReadRequest_clear(&req);
        return res;
    }

    /* Read and convert the DataTypeDefinitions */
    res = getRemoteDataTypes(client, &req, customTypes);
    UA_ReadRequest_clear(&req);
    return res;
}

/**** amalgamated original file "/src/util/ua_eventfilter_parser.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2023-2024 (c) Fraunhofer IOSB (Author: Florian Düwel)
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


/* Maximum nesting depth of the operand tree. Bounds the recursion when
 * resolving references and walking the tree, so that deeply nested expressions
 * (e.g. long operator chains) cannot overflow the native stack. */
#define UA_EVENTFILTER_MAXDEPTH 64

void
pos2lines(const UA_ByteString content, size_t pos,
          unsigned *outLine, unsigned *outCol) {
    unsigned line = 1, col = 1;
    for(size_t i = 0; i < pos; i++) {
        if(content.data[i] == '\n') {
            line++;
            col = 1;
        } else {
            col++;
        }
    }
    *outLine = line;
    *outCol = col;
}

static Operand *
newOperand(EFParseContext *ctx) {
    Operand *op = (Operand*)UA_calloc(1, sizeof(Operand));
    LIST_INSERT_HEAD(&ctx->operands, op, entries);
    ctx->operandsSize++;
    return op;
}

static Operand *
findOperand(EFParseContext *ctx, char *ref) {
    Operand *temp, *found = NULL;
    LIST_FOREACH(temp, &ctx->operands, entries) {
        if(!temp->ref || strcmp(temp->ref, ref) != 0)
            continue;
        if(found) {
            UA_LOG_ERROR(ctx->logger, UA_LOGCATEGORY_APPLICATION,
                         "Duplicate definition of operand reference %s", ref);
            return NULL;
        }
        found = temp;
    }
    if(!found) {
        UA_LOG_ERROR(ctx->logger, UA_LOGCATEGORY_APPLICATION,
                     "Failed to find the operand reference %s", ref);
    }
    return found;
}

static Operand *
resolveOperandRef(EFParseContext *ctx, Operand *op, size_t depth) {
    if(depth > UA_EVENTFILTER_MAXDEPTH || depth > ctx->operandsSize)
        return NULL; /* prevent infinite recursion */
    if(!op)
        return NULL;
    if(op->type != OT_REF)
        return op;
    return resolveOperandRef(ctx, findOperand(ctx, op->operand.ref), depth+1);
}

static void
deleteOperand(Operand *on) {
    UA_free(on->ref);
    if(on->type == OT_OPERATOR) {
        UA_free(on->operand.op.children);
    } else if(on->type == OT_REF) {
        UA_free(on->operand.ref);
    } else if(on->type == OT_SAO) {
        UA_SimpleAttributeOperand_clear(&on->operand.sao);
    } else if(on->type == OT_LITERAL) {
        UA_Variant_clear(&on->operand.literal);
    }
    UA_free(on);
}

void
EFParseContext_clear(EFParseContext *ctx) {
    Operand *temp, *temp1;
    LIST_FOREACH_SAFE(temp, &ctx->operands, entries, temp1) {
        LIST_REMOVE(temp, entries);
        deleteOperand(temp);
    }
}

void append_select(EFParseContext *ctx, Operand *on) {
    TAILQ_INSERT_TAIL(&ctx->select_operands, on, select_entries);
}

char *
save_string(char *str) {
    char *local_str = (char*) UA_calloc(strlen(str)+1, sizeof(char));
    strcpy(local_str, str);
    return local_str;
}

Operand *
create_operand(EFParseContext *ctx, OperandType ot) {
    Operand *on = newOperand(ctx);
    on->type = ot;
    return on;
}

Operand *
create_operator(EFParseContext *ctx, UA_FilterOperator fo) {
    Operand *on = create_operand(ctx, OT_OPERATOR);
    on->operand.op.filter = fo;
    return on;
}

void
append_operand(Operand *op, Operand *on) {
    Operator *optr = &op->operand.op;
    Operand **children_tmp = (Operand **)
        UA_realloc(optr->children, (optr->childrenSize + 1) * sizeof(Operand*));
    if(!children_tmp)
        return;
    optr->children = children_tmp;
    optr->children[optr->childrenSize] = on;
    optr->childrenSize++;
}

/* Count the number of elements for the filter. Mark all required elements that
 * appear in the hierarchy from the top element. */
static size_t
markPrinted(EFParseContext *ctx, Operand *top, size_t depth, UA_StatusCode *res) {
    if(depth > UA_EVENTFILTER_MAXDEPTH) {
        *res |= UA_STATUSCODE_BADINTERNALERROR; /* prevent stack overflow */
        return 0;
    }
    top = resolveOperandRef(ctx, top, 0);
    if(!top) {
        *res |= UA_STATUSCODE_BADINTERNALERROR;
        return 0;
    }
    if(top->type != OT_OPERATOR)
        return 0; /* Not an element but the operand of an element */
    if(top->operand.op.required)
        return 0; /* already visited */
    top->operand.op.required = true;
    size_t count = 1;
    for(size_t i = 0; i < top->operand.op.childrenSize; i++)
        count += markPrinted(ctx, top->operand.op.children[i], depth+1, res);
    return count;
}

/* Return the first printable operator from the list. It must be required and
 * all child-operators must be printed already. */
static Operator *
getPrintable(EFParseContext *ctx) {
    Operand *on;
    LIST_FOREACH(on, &ctx->operands, entries) {
        if(on->type != OT_OPERATOR)
            continue;

        Operator *op = &on->operand.op;
        if(!op->required || op->elementIndex > 0)
            continue; /* Not required or already printed */

        /* Check all children */
        size_t i = 0;
        for(; i < op->childrenSize; i++) {
            Operand *op_i = resolveOperandRef(ctx, op->children[i], 0);
            UA_assert(op_i); /* Must resolve. Otherwise markPrinted would have
                              * found error. */
            if(op_i->type == OT_OPERATOR && op_i->operand.op.elementIndex == 0)
                break;
        }
        if(i == op->childrenSize)
            return op; /* All children are ready */
    }
    return NULL;
}

static UA_StatusCode
printOperator(EFParseContext *ctx, UA_ContentFilterElement *elm, Operator *op) {
    UA_ContentFilterElement_init(elm);
    elm->filterOperandsSize = op->childrenSize;
    elm->filterOperands = (UA_ExtensionObject*)
        UA_calloc(op->childrenSize, sizeof(UA_ExtensionObject));
    elm->filterOperator = op->filter;
    for(size_t i = 0; i < op->childrenSize; i++) {
        Operand *op_i = resolveOperandRef(ctx, op->children[i], 0);
        if(op_i->type == OT_OPERATOR) {
            UA_ElementOperand *elmo = UA_ElementOperand_new();
            elmo->index = (UA_UInt32)op_i->operand.op.elementIndex;
            UA_ExtensionObject_setValue(&elm->filterOperands[i], elmo,
                                        &UA_TYPES[UA_TYPES_ELEMENTOPERAND]);
        } else if(op_i->type == OT_SAO) {
            UA_SimpleAttributeOperand *sao = UA_SimpleAttributeOperand_new();
            UA_SimpleAttributeOperand_copy(&op_i->operand.sao, sao);
            UA_ExtensionObject_setValue(&elm->filterOperands[i], sao,
                                        &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
        } else if(op_i->type == OT_LITERAL) {
            UA_LiteralOperand *lit = UA_LiteralOperand_new();
            UA_Variant_copy(&op_i->operand.literal, &lit->value);
            UA_ExtensionObject_setValue(&elm->filterOperands[i], lit,
                                        &UA_TYPES[UA_TYPES_LITERALOPERAND]);
        }
    }
    return UA_STATUSCODE_GOOD;
}

// #define UA_EVENTFILTERPARSER_DEBUG 1

#ifdef UA_EVENTFILTERPARSER_DEBUG
#include <stdio.h>
static void
debug_element(Operand *on) {
    if(on->ref)
        printf("%s: ", on->ref);
    if(on->type == OT_REF) {
        printf("-> %s\n", on->operand.ref);
    } else if(on->type == OT_OPERATOR) {
        printf("Operator %i\n", (int)on->operand.op.filter);
    } else if(on->type == OT_SAO) {
        printf("SAO\n");
    } else if(on->type == OT_LITERAL) {
        printf("Literal\n");
    }
}
#endif

UA_StatusCode
create_filter(EFParseContext *ctx, UA_EventFilter *filter) {
#ifdef UA_EVENTFILTERPARSER_DEBUG
    Operand *temp;
    LIST_FOREACH(temp, &ctx->operands, entries) {
        debug_element(temp);
    }
#endif

    /* Create the select filter */
    Operand *sao;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    TAILQ_FOREACH(sao, &ctx->select_operands, select_entries) {
        sao = resolveOperandRef(ctx, sao, 0);
        if(!sao)
            return UA_STATUSCODE_BADINTERNALERROR;
        if(sao->type != OT_SAO) {
            UA_LOG_ERROR(ctx->logger, UA_LOGCATEGORY_APPLICATION,
                         "The select clause must only contain SimpleAttributeOperands");
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        res = UA_Array_append((void **)&filter->selectClauses,
                              &filter->selectClausesSize, &sao->operand.sao,
                              &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Create the where filter */
    if(!ctx->top)
        return UA_STATUSCODE_GOOD; /* No where clause */

    Operand *top = resolveOperandRef(ctx, ctx->top, 0);
    if(!top || top->type != OT_OPERATOR) {
        UA_LOG_ERROR(ctx->logger, UA_LOGCATEGORY_APPLICATION,
                     "The where clause has no top-level operator");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    size_t count = markPrinted(ctx, top, 0, &res); /* Count relevant filter elements */
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Allocate the elements array */
    filter->whereClause.elements = (UA_ContentFilterElement*)
        UA_Array_new(count, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]);
    filter->whereClause.elementsSize = count;

    /* Get the next printable operator and print it */
    Operator *printable;
    while(count > 0 && (printable = getPrintable(ctx))) {
        count--;
        res |= printOperator(ctx, &filter->whereClause.elements[count], printable);
        printable->elementIndex = count;
    }

    /* Cycles are not allowed. Detected if we could not print all relevant
     * elements */
    if(count > 0) {
        UA_LOG_ERROR(ctx->logger, UA_LOGCATEGORY_APPLICATION,
                     "Cyclic operand references detected");
        res |= UA_STATUSCODE_BADINTERNALERROR;
    }

    return res;
}

/**** amalgamated original file "/src/util/ua_eventfilter_lex.c" ****/

/* Generated by re2c 4.3 */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


/* This compilation unit uses the re2c lexer generator. The final C source is
 * generated with the following script:
 *
 *   re2c -i --no-generation-date ua_eventfilter_lex.re > ua_eventfilter_lex.c
 *
 * In order that users of the SDK don't need to install re2c, always commit a
 * recent ua_eventfilter_lex.c if changes are made to the lexer. */

/* Undefine macros to prevent clashes in the amalgamation build */
#undef YYPEEK
#undef YYSKIP
#undef YYBACKUP
#undef YYRESTORE
#undef YYSHIFT
#undef YYSTAGP
#undef YYSTAGN
#undef YYSHIFTSTAG
#undef YYRESTORETAG
#define YYPEEK() (pos < end) ? *pos: 0
#define YYSKIP() ++pos;
#define YYBACKUP() m = pos;
#define YYRESTORE() pos = m;
#define YYSHIFT(shift) pos += shift
#define YYSTAGP(t) t = pos
#define YYSTAGN(t) t = NULL
#define YYSHIFTSTAG(t, shift) t += shift
#define YYRESTORETAG(t) pos = t;



UA_StatusCode
UA_EventFilter_skip(const UA_ByteString content, size_t *offset,
                    EFParseContext *ctx) {
    const u8 *pos = &content.data[*offset];
    const u8 *end = &content.data[content.length];

  begin:
    *offset = (uintptr_t)(pos - content.data);
    size_t initial = *offset;

    
{
	u8 yych;
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy3;
		case '/': goto yy5;
		default: goto yy1;
	}
yy1:
	YYSKIP();
yy2:
	{ return UA_STATUSCODE_GOOD; }
yy3:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy3;
		default: goto yy4;
	}
yy4:
	{ goto begin; }
yy5:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '*': goto yy6;
		case '/': goto yy7;
		default: goto yy2;
	}
yy6:
	YYSKIP();
	{ for(; pos < end - 1; pos++)
           { if(pos[0] == '*' && pos[1] == '/') { pos += 2; goto begin; } }
           unsigned c = 0, l = 0;
           pos2lines(content, initial, &l, &c);
           UA_LOG_ERROR(ctx->logger, UA_LOGCATEGORY_APPLICATION,
                        "The comment starting at line %u, column %u "
                        "never terminates", l, c);
           return UA_STATUSCODE_BADINTERNALERROR;
         }
yy7:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n':
		case '\r': goto yy8;
		default: goto yy7;
	}
yy8:
	{ goto begin; }
}

}

int
UA_EventFilter_lex(const UA_ByteString content, size_t *offset,
                   EFParseContext *ctx, Operand **token) {
    const u8 *pos = &content.data[*offset];
    const u8 *end = &content.data[content.length];
    const u8 *m, *b; /* marker, match begin */
    const u8 *yyt1 = NULL;
    const UA_DataType *lt; /* literal type */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_ByteString match;
    UA_FilterOperator f;

    int tokenId = 0;
    while(true) {
        /* Store the beginning */
        b = pos;

        
{
	u8 yych;
	unsigned int yyaccept = 0;
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '.': goto yy10;
		case '!': goto yy13;
		case '"': goto yy15;
		case '#':
		case '/': goto yy16;
		case '$': goto yy19;
		case '&': goto yy20;
		case '\'': goto yy22;
		case '(': goto yy23;
		case ')': goto yy24;
		case ',': goto yy25;
		case '-': goto yy26;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy27;
		case ':': goto yy29;
		case '<': goto yy30;
		case '=': goto yy32;
		case '>': goto yy33;
		case 'A':
		case 'a': goto yy35;
		case 'B': goto yy36;
		case 'C':
		case 'c': goto yy37;
		case 'D':
		case 'd': goto yy38;
		case 'E':
		case 'e': goto yy39;
		case 'F':
		case 'f': goto yy40;
		case 'G': goto yy41;
		case 'I': goto yy42;
		case 'L':
		case 'l': goto yy43;
		case 'N': goto yy44;
		case 'O':
		case 'o': goto yy45;
		case 'Q':
		case 'q': goto yy46;
		case 'S': goto yy47;
		case 'T':
		case 't': goto yy48;
		case 'U':
		case 'u': goto yy49;
		case 'W':
		case 'w': goto yy50;
		case '[': goto yy51;
		case ']': goto yy52;
		case 'b': goto yy53;
		case 'g': goto yy54;
		case 'i': goto yy55;
		case 'n': goto yy56;
		case 's': goto yy57;
		case '{': goto yy58;
		case '|': goto yy60;
		default: goto yy12;
	}
yy10:
	YYSKIP();
yy11:
	{ goto finish; }
yy12:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		default: goto yy63;
	}
yy13:
	YYSKIP();
yy14:
	{ f = UA_FILTEROPERATOR_NOT;     tokenId = EF_TOK_NOT;     goto make_op; }
yy15:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	if (yych <= 0x00) goto yy11;
	goto yy67;
yy16:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
yy17:
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy18;
		case '&': goto yy75;
		case '[': goto yy76;
		default: goto yy16;
	}
yy18:
	{ goto sao; }
yy19:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case '_':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy77;
		default: goto yy63;
	}
yy20:
	yyaccept = 2;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy21;
		case '&': goto yy79;
		default: goto yy62;
	}
yy21:
	{ f = UA_FILTEROPERATOR_BITWISEAND;                        goto binary_op; }
yy22:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	if (yych <= 0x00) goto yy11;
	goto yy82;
yy23:
	YYSKIP();
	{ tokenId = EF_TOK_LPAREN;     goto finish; }
yy24:
	YYSKIP();
	{ tokenId = EF_TOK_RPAREN;     goto finish; }
yy25:
	YYSKIP();
	{ tokenId = EF_TOK_COMMA;      goto finish; }
yy26:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '[':
		case ']': goto yy11;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy27;
		case '>': goto yy90;
		default: goto yy63;
	}
yy27:
	yyaccept = 3;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy28;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy27;
		default: goto yy62;
	}
yy28:
	{ lt = &UA_TYPES[UA_TYPES_INT32]; goto lit; }
yy29:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy92;
		default: goto yy11;
	}
yy30:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy93;
		default: goto yy31;
	}
yy31:
	{ f = UA_FILTEROPERATOR_LESSTHAN;                          goto binary_op; }
yy32:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case '=': goto yy95;
		default: goto yy63;
	}
yy33:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy97;
		default: goto yy34;
	}
yy34:
	{ f = UA_FILTEROPERATOR_GREATERTHAN;                       goto binary_op; }
yy35:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'N':
		case 'n': goto yy99;
		default: goto yy63;
	}
yy36:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'E':
		case 'e': goto yy100;
		case 'I':
		case 'i': goto yy101;
		case 'O':
		case 'o': goto yy102;
		case 'Y':
		case 'y': goto yy103;
		default: goto yy63;
	}
yy37:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'A':
		case 'a': goto yy104;
		default: goto yy63;
	}
yy38:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'A':
		case 'a': goto yy105;
		case 'O':
		case 'o': goto yy106;
		default: goto yy63;
	}
yy39:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'Q':
		case 'q': goto yy107;
		case 'X':
		case 'x': goto yy108;
		default: goto yy63;
	}
yy40:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'A':
		case 'a': goto yy109;
		case 'L':
		case 'l': goto yy110;
		case 'O':
		case 'o': goto yy111;
		default: goto yy63;
	}
yy41:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'R':
		case 'r': goto yy112;
		case 'U':
		case 'u': goto yy113;
		default: goto yy63;
	}
yy42:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'N':
		case 'n': goto yy114;
		case 'S':
		case 's': goto yy115;
		default: goto yy63;
	}
yy43:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'E':
		case 'e': goto yy116;
		case 'I':
		case 'i': goto yy117;
		case 'O':
		case 'o': goto yy118;
		default: goto yy63;
	}
yy44:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'O':
		case 'o': goto yy119;
		default: goto yy63;
	}
yy45:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'F':
		case 'f': goto yy120;
		case 'R':
		case 'r': goto yy121;
		default: goto yy63;
	}
yy46:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'U':
		case 'u': goto yy123;
		default: goto yy63;
	}
yy47:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'B':
		case 'b': goto yy124;
		case 'E':
		case 'e': goto yy125;
		case 'T':
		case 't': goto yy126;
		default: goto yy63;
	}
yy48:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'R':
		case 'r': goto yy127;
		default: goto yy63;
	}
yy49:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'I':
		case 'i': goto yy128;
		default: goto yy63;
	}
yy50:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'H':
		case 'h': goto yy129;
		default: goto yy63;
	}
yy51:
	YYSKIP();
	{ tokenId = EF_TOK_LBRACKET;   goto finish; }
yy52:
	YYSKIP();
	{ tokenId = EF_TOK_RBRACKET;   goto finish; }
yy53:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case '=': goto yy130;
		case 'E':
		case 'e': goto yy100;
		case 'I':
		case 'i': goto yy101;
		case 'O':
		case 'o': goto yy102;
		case 'Y':
		case 'y': goto yy103;
		default: goto yy63;
	}
yy54:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case '=': goto yy130;
		case 'R':
		case 'r': goto yy112;
		case 'U':
		case 'u': goto yy113;
		default: goto yy63;
	}
yy55:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case '=': goto yy130;
		case 'N':
		case 'n': goto yy114;
		case 'S':
		case 's': goto yy115;
		default: goto yy63;
	}
yy56:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case 'O':
		case 'o': goto yy119;
		case 's': goto yy131;
		default: goto yy63;
	}
yy57:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy11;
		case '=': goto yy130;
		case 'B':
		case 'b': goto yy124;
		case 'E':
		case 'e': goto yy125;
		case 'T':
		case 't': goto yy126;
		default: goto yy63;
	}
yy58:
	yyaccept = 4;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy59;
		default: goto yy63;
	}
yy59:
	{ goto json; }
yy60:
	yyaccept = 5;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy61;
		case '|': goto yy121;
		default: goto yy63;
	}
yy61:
	{ f = UA_FILTEROPERATOR_BITWISEOR;                         goto binary_op; }
yy62:
	YYSKIP();
	yych = YYPEEK();
yy63:
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		default: goto yy62;
	}
yy64:
	YYRESTORE();
	switch (yyaccept) {
		case 0: goto yy11;
		case 1: goto yy18;
		case 2: goto yy21;
		case 3: goto yy28;
		case 4: goto yy59;
		case 5: goto yy61;
		case 6: goto yy71;
		case 7: goto yy78;
		case 8: goto yy80;
		case 9: goto yy88;
		case 10: goto yy96;
		case 11: goto yy122;
		case 12: goto yy14;
		case 13: goto yy179;
		case 14: goto yy91;
		case 15: goto yy198;
		case 16: goto yy210;
		case 17: goto yy220;
		case 18: goto yy263;
		case 19: goto yy273;
		case 20: goto yy276;
		case 21: goto yy284;
		case 22: goto yy289;
		case 23: goto yy300;
		case 24: goto yy306;
		case 25: goto yy315;
		case 26: goto yy320;
		case 27: goto yy325;
		case 28: goto yy330;
		case 29:
			YYSTAGP(yyt1);
			goto yy336;
		case 30: goto yy341;
		case 31: goto yy345;
		case 32: goto yy364;
		case 33: goto yy31;
		case 34: goto yy336;
		case 35: goto yy383;
		case 36: goto yy386;
		case 37: goto yy389;
		case 38: goto yy407;
		case 39: goto yy414;
		case 40: goto yy427;
		case 41: goto yy34;
		case 42: goto yy465;
		case 43: goto yy468;
		case 44: goto yy476;
		case 45:
			YYSTAGP(yyt1);
			goto yy491;
		case 46:
			YYSTAGP(yyt1);
			goto yy494;
		case 47: goto yy94;
		case 48: goto yy501;
		case 49: goto yy491;
		case 50: goto yy494;
		default: goto yy98;
	}
yy65:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy62;
	}
yy66:
	YYSKIP();
	yych = YYPEEK();
yy67:
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy68;
		case '"': goto yy70;
		case '#':
		case '/': goto yy72;
		case '&': goto yy73;
		case '\\': goto yy74;
		default: goto yy66;
	}
yy68:
	YYSKIP();
	yych = YYPEEK();
yy69:
	switch (yych) {
		case 0x00: goto yy64;
		case '"': goto yy132;
		case '\\': goto yy133;
		default: goto yy68;
	}
yy70:
	yyaccept = 6;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy71;
		default: goto yy63;
	}
yy71:
	{ lt = &UA_TYPES[UA_TYPES_STRING]; goto lit; }
yy72:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy68;
		case '"': goto yy16;
		case '&': goto yy134;
		case '[': goto yy135;
		case '\\': goto yy136;
		default: goto yy72;
	}
yy73:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy68;
		case '"': goto yy70;
		case '\\': goto yy74;
		default: goto yy66;
	}
yy74:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy68;
		case '"': goto yy137;
		case '#':
		case '/': goto yy72;
		case '&': goto yy73;
		case '\\': goto yy74;
		default: goto yy66;
	}
yy75:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy16;
	}
yy76:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case ']': goto yy64;
		default: goto yy139;
	}
yy77:
	yyaccept = 7;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy78;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case '_':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy77;
		default: goto yy62;
	}
yy78:
	{ goto namedoperand; }
yy79:
	yyaccept = 8;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy80;
		default: goto yy63;
	}
yy80:
	{ f = UA_FILTEROPERATOR_AND;     tokenId = EF_TOK_AND;     goto make_op; }
yy81:
	YYSKIP();
	yych = YYPEEK();
yy82:
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy83;
		case '#':
		case '/': goto yy85;
		case '&': goto yy86;
		case '\'': goto yy87;
		case '\\': goto yy89;
		default: goto yy81;
	}
yy83:
	YYSKIP();
	yych = YYPEEK();
yy84:
	switch (yych) {
		case 0x00: goto yy64;
		case '\'': goto yy140;
		case '\\': goto yy141;
		default: goto yy83;
	}
yy85:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy83;
		case '&': goto yy142;
		case '\'': goto yy16;
		case '[': goto yy143;
		case '\\': goto yy144;
		default: goto yy85;
	}
yy86:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy83;
		case '\'': goto yy87;
		case '\\': goto yy89;
		default: goto yy81;
	}
yy87:
	yyaccept = 9;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy88;
		default: goto yy63;
	}
yy88:
	{ lt = &UA_TYPES[UA_TYPES_STRING]; goto lit; }
yy89:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy83;
		case '#':
		case '/': goto yy85;
		case '&': goto yy86;
		case '\'': goto yy145;
		case '\\': goto yy89;
		default: goto yy81;
	}
yy90:
	YYSKIP();
yy91:
	{ f = UA_FILTEROPERATOR_CAST;                              goto binary_op; }
yy92:
	YYSKIP();
	{ tokenId = EF_TOK_COLONEQUAL; goto finish; }
yy93:
	YYSKIP();
yy94:
	{ f = UA_FILTEROPERATOR_LESSTHANOREQUAL;                   goto binary_op; }
yy95:
	yyaccept = 10;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy96;
		default: goto yy63;
	}
yy96:
	{ f = UA_FILTEROPERATOR_EQUALS;                            goto binary_op; }
yy97:
	YYSKIP();
yy98:
	{ f = UA_FILTEROPERATOR_GREATERTHANOREQUAL;                goto binary_op; }
yy99:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy79;
		default: goto yy63;
	}
yy100:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy146;
		default: goto yy63;
	}
yy101:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy147;
		default: goto yy63;
	}
yy102:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'O':
		case 'o': goto yy148;
		default: goto yy63;
	}
yy103:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy149;
		default: goto yy63;
	}
yy104:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy150;
		default: goto yy63;
	}
yy105:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy151;
		default: goto yy63;
	}
yy106:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy152;
		default: goto yy63;
	}
yy107:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy153;
		default: goto yy63;
	}
yy108:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'P':
		case 'p': goto yy154;
		default: goto yy63;
	}
yy109:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy155;
		default: goto yy63;
	}
yy110:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'O':
		case 'o': goto yy156;
		default: goto yy63;
	}
yy111:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy157;
		default: goto yy63;
	}
yy112:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy158;
		default: goto yy63;
	}
yy113:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy159;
		default: goto yy63;
	}
yy114:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy160;
		case 'T':
		case 't': goto yy161;
		default: goto yy63;
	}
yy115:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy162;
		default: goto yy63;
	}
yy116:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy163;
		default: goto yy63;
	}
yy117:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'K':
		case 'k': goto yy164;
		default: goto yy63;
	}
yy118:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'C':
		case 'c': goto yy165;
		default: goto yy63;
	}
yy119:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy166;
		case 'T':
		case 't': goto yy167;
		default: goto yy63;
	}
yy120:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy168;
		default: goto yy63;
	}
yy121:
	yyaccept = 11;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy122;
		default: goto yy63;
	}
yy122:
	{ f = UA_FILTEROPERATOR_OR;      tokenId = EF_TOK_OR;      goto make_op; }
yy123:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy169;
		default: goto yy63;
	}
yy124:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'Y':
		case 'y': goto yy170;
		default: goto yy63;
	}
yy125:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy171;
		default: goto yy63;
	}
yy126:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy172;
		case 'R':
		case 'r': goto yy173;
		default: goto yy63;
	}
yy127:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy174;
		default: goto yy63;
	}
yy128:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy175;
		default: goto yy63;
	}
yy129:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy176;
		default: goto yy63;
	}
yy130:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		default: goto yy178;
	}
yy131:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy181;
		default: goto yy63;
	}
yy132:
	YYSKIP();
	goto yy71;
yy133:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '"': goto yy182;
		case '\\': goto yy133;
		default: goto yy68;
	}
yy134:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy68;
		case '"': goto yy16;
		case '\\': goto yy136;
		default: goto yy72;
	}
yy135:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy183;
		default: goto yy69;
	}
yy136:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy68;
		case '&': goto yy134;
		case '[': goto yy135;
		case '\\': goto yy136;
		default: goto yy72;
	}
yy137:
	yyaccept = 6;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy71;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy68;
		case '"': goto yy70;
		case '#':
		case '/': goto yy72;
		case '&': goto yy73;
		case '\\': goto yy74;
		default: goto yy66;
	}
yy138:
	YYSKIP();
	yych = YYPEEK();
yy139:
	switch (yych) {
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy138;
		case ']': goto yy184;
		default: goto yy64;
	}
yy140:
	YYSKIP();
	goto yy88;
yy141:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\'': goto yy185;
		case '\\': goto yy141;
		default: goto yy83;
	}
yy142:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy83;
		case '\'': goto yy16;
		case '\\': goto yy144;
		default: goto yy85;
	}
yy143:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy186;
		default: goto yy84;
	}
yy144:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy83;
		case '&': goto yy142;
		case '[': goto yy143;
		case '\\': goto yy144;
		default: goto yy85;
	}
yy145:
	yyaccept = 9;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy88;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy83;
		case '#':
		case '/': goto yy85;
		case '&': goto yy86;
		case '\'': goto yy87;
		case '\\': goto yy89;
		default: goto yy81;
	}
yy146:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'W':
		case 'w': goto yy187;
		default: goto yy63;
	}
yy147:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'W':
		case 'w': goto yy188;
		default: goto yy63;
	}
yy148:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy189;
		default: goto yy63;
	}
yy149:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy190;
		default: goto yy63;
	}
yy150:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy191;
		default: goto yy63;
	}
yy151:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy192;
		default: goto yy63;
	}
yy152:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'B':
		case 'b': goto yy193;
		default: goto yy63;
	}
yy153:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy194;
		default: goto yy63;
	}
yy154:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy195;
		default: goto yy63;
	}
yy155:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy174;
		default: goto yy63;
	}
yy156:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy196;
		default: goto yy63;
	}
yy157:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
			YYSTAGP(yyt1);
			goto yy197;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ':
			YYSTAGP(yyt1);
			goto yy199;
		case '?':
			YYSTAGP(yyt1);
			goto yy200;
		default: goto yy63;
	}
yy158:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy201;
		default: goto yy63;
	}
yy159:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy202;
		default: goto yy63;
	}
yy160:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy203;
		default: goto yy63;
	}
yy161:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '1': goto yy204;
		case '3': goto yy205;
		case '6': goto yy206;
		default: goto yy63;
	}
yy162:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy207;
		default: goto yy63;
	}
yy163:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy208;
		default: goto yy63;
	}
yy164:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy209;
		default: goto yy63;
	}
yy165:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy211;
		default: goto yy63;
	}
yy166:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy212;
		default: goto yy63;
	}
yy167:
	yyaccept = 12;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy14;
		default: goto yy63;
	}
yy168:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'Y':
		case 'y': goto yy213;
		default: goto yy63;
	}
yy169:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy214;
		default: goto yy63;
	}
yy170:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy215;
		default: goto yy63;
	}
yy171:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy216;
		default: goto yy63;
	}
yy172:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy217;
		default: goto yy63;
	}
yy173:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy218;
		default: goto yy63;
	}
yy174:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy219;
		default: goto yy63;
	}
yy175:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy221;
		default: goto yy63;
	}
yy176:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy222;
		default: goto yy63;
	}
yy177:
	yyaccept = 13;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
yy178:
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy179;
		case '#':
		case '/': goto yy16;
		case '&': goto yy180;
		default: goto yy177;
	}
yy179:
	{ lt = &UA_TYPES[UA_TYPES_NODEID]; goto lit; }
yy180:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy177;
	}
yy181:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy223;
		default: goto yy63;
	}
yy182:
	yyaccept = 6;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy71;
		case '"': goto yy132;
		case '\\': goto yy133;
		default: goto yy68;
	}
yy183:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '"': goto yy132;
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy183;
		case '\\': goto yy133;
		case ']': goto yy224;
		default: goto yy68;
	}
yy184:
	YYSKIP();
	goto yy18;
yy185:
	yyaccept = 9;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy88;
		case '\'': goto yy140;
		case '\\': goto yy141;
		default: goto yy83;
	}
yy186:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\'': goto yy140;
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy186;
		case '\\': goto yy141;
		case ']': goto yy225;
		default: goto yy83;
	}
yy187:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy226;
		default: goto yy63;
	}
yy188:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy227;
		default: goto yy63;
	}
yy189:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy228;
		default: goto yy63;
	}
yy190:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy229;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy230;
		case 'S':
		case 's': goto yy231;
		default: goto yy63;
	}
yy191:
	yyaccept = 14;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy91;
		default: goto yy63;
	}
yy192:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy232;
		default: goto yy63;
	}
yy193:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy233;
		default: goto yy63;
	}
yy194:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy234;
		default: goto yy63;
	}
yy195:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy235;
		default: goto yy63;
	}
yy196:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy236;
		default: goto yy63;
	}
yy197:
	yyaccept = 15;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy198;
		case 0x08: goto yy197;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy199;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		default: goto yy62;
	}
yy198:
	YYRESTORETAG(yyt1);
	{ tokenId = EF_TOK_FOR;    goto finish; }
yy199:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy199;
		default: goto yy198;
	}
yy200:
	yyaccept = 15;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy198;
		default: goto yy63;
	}
yy201:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy237;
		default: goto yy63;
	}
yy202:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy238;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy239;
		default: goto yy63;
	}
yy203:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy240;
		default: goto yy63;
	}
yy204:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '6': goto yy241;
		default: goto yy63;
	}
yy205:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '2': goto yy242;
		default: goto yy63;
	}
yy206:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '4': goto yy243;
		default: goto yy63;
	}
yy207:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy244;
		default: goto yy63;
	}
yy208:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy245;
		default: goto yy63;
	}
yy209:
	yyaccept = 16;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy210;
		default: goto yy63;
	}
yy210:
	{ f = UA_FILTEROPERATOR_LIKE;                              goto binary_op; }
yy211:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy246;
		default: goto yy63;
	}
yy212:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy247;
		default: goto yy63;
	}
yy213:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'P':
		case 'p': goto yy248;
		default: goto yy63;
	}
yy214:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy249;
		default: goto yy63;
	}
yy215:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy250;
		default: goto yy63;
	}
yy216:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'C':
		case 'c': goto yy251;
		default: goto yy63;
	}
yy217:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy252;
		default: goto yy63;
	}
yy218:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy253;
		default: goto yy63;
	}
yy219:
	yyaccept = 17;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy220;
		default: goto yy63;
	}
yy220:
	{ lt = &UA_TYPES[UA_TYPES_BOOLEAN]; goto lit; }
yy221:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '1': goto yy254;
		case '3': goto yy255;
		case '6': goto yy256;
		default: goto yy63;
	}
yy222:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy257;
		default: goto yy63;
	}
yy223:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy223;
		case ';': goto yy258;
		default: goto yy62;
	}
yy224:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	if (yych <= 0x00) goto yy18;
	goto yy69;
yy225:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	if (yych <= 0x00) goto yy18;
	goto yy84;
yy226:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy259;
		default: goto yy63;
	}
yy227:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy260;
		default: goto yy63;
	}
yy228:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy261;
		default: goto yy63;
	}
yy229:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy229;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy230;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy262;
		default: goto yy62;
	}
yy230:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy230;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy264;
		default: goto yy64;
	}
yy231:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy265;
		default: goto yy63;
	}
yy232:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy266;
		default: goto yy63;
	}
yy233:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy267;
		default: goto yy63;
	}
yy234:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy95;
		default: goto yy63;
	}
yy235:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy268;
		default: goto yy63;
	}
yy236:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy269;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy270;
		default: goto yy63;
	}
yy237:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy271;
		default: goto yy63;
	}
yy238:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy238;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy239;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '-':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy272;
		default: goto yy62;
	}
yy239:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy239;
		case '-':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy274;
		default: goto yy64;
	}
yy240:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy275;
		default: goto yy63;
	}
yy241:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy277;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy278;
		default: goto yy63;
	}
yy242:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy279;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy280;
		default: goto yy63;
	}
yy243:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy281;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy282;
		default: goto yy63;
	}
yy244:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy283;
		default: goto yy63;
	}
yy245:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'H':
		case 'h': goto yy285;
		default: goto yy63;
	}
yy246:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy286;
		default: goto yy63;
	}
yy247:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy287;
		default: goto yy63;
	}
yy248:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy288;
		default: goto yy63;
	}
yy249:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'F':
		case 'f': goto yy290;
		default: goto yy63;
	}
yy250:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy291;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy292;
		default: goto yy63;
	}
yy251:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy293;
		default: goto yy63;
	}
yy252:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy294;
		default: goto yy63;
	}
yy253:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'G':
		case 'g': goto yy295;
		default: goto yy63;
	}
yy254:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '6': goto yy296;
		default: goto yy63;
	}
yy255:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '2': goto yy297;
		default: goto yy63;
	}
yy256:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '4': goto yy298;
		default: goto yy63;
	}
yy257:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
			YYSTAGP(yyt1);
			goto yy299;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ':
			YYSTAGP(yyt1);
			goto yy301;
		case '(':
			YYSTAGP(yyt1);
			goto yy302;
		case '?':
			YYSTAGP(yyt1);
			goto yy303;
		default: goto yy63;
	}
yy258:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's': goto yy304;
		default: goto yy63;
	}
yy259:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy305;
		default: goto yy63;
	}
yy260:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy307;
		default: goto yy63;
	}
yy261:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy308;
		default: goto yy63;
	}
yy262:
	yyaccept = 18;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy263;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy262;
		default: goto yy62;
	}
yy263:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_BYTE];           goto lit; }
yy264:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy264;
		default: goto yy263;
	}
yy265:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy309;
		default: goto yy63;
	}
yy266:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'M':
		case 'm': goto yy310;
		default: goto yy63;
	}
yy267:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy311;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy312;
		default: goto yy63;
	}
yy268:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy313;
		default: goto yy63;
	}
yy269:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy269;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy270;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '+':
		case '-':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e':
			YYSTAGP(yyt1);
			goto yy314;
		case '.':
			YYSTAGP(yyt1);
			goto yy316;
		default: goto yy62;
	}
yy270:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy270;
		case '+':
		case '-':
		case '.':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e':
			YYSTAGP(yyt1);
			goto yy316;
		default: goto yy64;
	}
yy271:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy317;
		default: goto yy63;
	}
yy272:
	yyaccept = 19;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy273;
		default: goto yy63;
	}
yy273:
	YYSTAGP(b);
	YYSHIFTSTAG(b, -1);
	{ lt = &UA_TYPES[UA_TYPES_GUID];           goto lit; }
yy274:
	YYSKIP();
	goto yy273;
yy275:
	yyaccept = 20;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy276;
		default: goto yy63;
	}
yy276:
	{ f = UA_FILTEROPERATOR_INLIST;  tokenId = EF_TOK_INLIST;  goto make_op; }
yy277:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy277;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy278;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '-':
			YYSTAGP(yyt1);
			goto yy318;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy319;
		default: goto yy62;
	}
yy278:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy278;
		case '-':
			YYSTAGP(yyt1);
			goto yy321;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy322;
		default: goto yy64;
	}
yy279:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy279;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy280;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '-':
			YYSTAGP(yyt1);
			goto yy323;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy324;
		default: goto yy62;
	}
yy280:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy280;
		case '-':
			YYSTAGP(yyt1);
			goto yy326;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy327;
		default: goto yy64;
	}
yy281:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy281;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy282;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '-':
			YYSTAGP(yyt1);
			goto yy328;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy329;
		default: goto yy62;
	}
yy282:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy282;
		case '-':
			YYSTAGP(yyt1);
			goto yy331;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy332;
		default: goto yy64;
	}
yy283:
	yyaccept = 21;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy284;
		default: goto yy63;
	}
yy284:
	{ f = UA_FILTEROPERATOR_ISNULL;                            goto unary_op; }
yy285:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy333;
		default: goto yy63;
	}
yy286:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'Z':
		case 'z': goto yy334;
		default: goto yy63;
	}
yy287:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy335;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy337;
		default: goto yy63;
	}
yy288:
	yyaccept = 22;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy289;
		default: goto yy63;
	}
yy289:
	{ f = UA_FILTEROPERATOR_OFTYPE;                            goto unary_op; }
yy290:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy338;
		default: goto yy63;
	}
yy291:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy291;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy292;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '-':
			YYSTAGP(yyt1);
			goto yy339;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy340;
		default: goto yy62;
	}
yy292:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy292;
		case '-':
			YYSTAGP(yyt1);
			goto yy342;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy343;
		default: goto yy64;
	}
yy293:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
			YYSTAGP(yyt1);
			goto yy344;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ':
			YYSTAGP(yyt1);
			goto yy346;
		case '?':
			YYSTAGP(yyt1);
			goto yy347;
		default: goto yy63;
	}
yy294:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'C':
		case 'c': goto yy348;
		default: goto yy63;
	}
yy295:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy349;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy350;
		default: goto yy63;
	}
yy296:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy351;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy352;
		default: goto yy63;
	}
yy297:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy353;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy354;
		default: goto yy63;
	}
yy298:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy355;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy356;
		default: goto yy63;
	}
yy299:
	yyaccept = 23;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy300;
		case 0x08: goto yy299;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy301;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		default: goto yy62;
	}
yy300:
	YYRESTORETAG(yyt1);
	{ tokenId = EF_TOK_WHERE;  goto finish; }
yy301:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy301;
		default: goto yy300;
	}
yy302:
	YYSKIP();
	goto yy300;
yy303:
	yyaccept = 23;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy300;
		default: goto yy63;
	}
yy304:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy130;
		default: goto yy63;
	}
yy305:
	yyaccept = 24;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy306;
		default: goto yy63;
	}
yy306:
	{ f = UA_FILTEROPERATOR_BETWEEN; tokenId = EF_TOK_BETWEEN; goto make_op; }
yy307:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy357;
		case 'O':
		case 'o': goto yy358;
		default: goto yy63;
	}
yy308:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy359;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy360;
		default: goto yy63;
	}
yy309:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy361;
		default: goto yy63;
	}
yy310:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy362;
		default: goto yy63;
	}
yy311:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy311;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy312;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '+':
		case '-':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e':
			YYSTAGP(yyt1);
			goto yy363;
		case '.':
			YYSTAGP(yyt1);
			goto yy365;
		default: goto yy62;
	}
yy312:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy312;
		case '+':
		case '-':
		case '.':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e':
			YYSTAGP(yyt1);
			goto yy365;
		default: goto yy64;
	}
yy313:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy366;
		default: goto yy63;
	}
yy314:
	yyaccept = 25;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy315;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '+':
		case '-':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e': goto yy314;
		case '.': goto yy316;
		default: goto yy62;
	}
yy315:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_FLOAT];          goto lit; }
yy316:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '+':
		case '-':
		case '.':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e': goto yy316;
		default: goto yy315;
	}
yy317:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy367;
		default: goto yy63;
	}
yy318:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy319;
		default: goto yy63;
	}
yy319:
	yyaccept = 26;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy320;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy319;
		default: goto yy62;
	}
yy320:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_INT16];          goto lit; }
yy321:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy322;
		default: goto yy64;
	}
yy322:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy322;
		default: goto yy320;
	}
yy323:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy324;
		default: goto yy63;
	}
yy324:
	yyaccept = 27;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy325;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy324;
		default: goto yy62;
	}
yy325:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_INT32];          goto lit; }
yy326:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy327;
		default: goto yy64;
	}
yy327:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy327;
		default: goto yy325;
	}
yy328:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy329;
		default: goto yy63;
	}
yy329:
	yyaccept = 28;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy330;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy329;
		default: goto yy62;
	}
yy330:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_INT64];          goto lit; }
yy331:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy332;
		default: goto yy64;
	}
yy332:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy332;
		default: goto yy330;
	}
yy333:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy368;
		default: goto yy63;
	}
yy334:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy369;
		default: goto yy63;
	}
yy335:
	yyaccept = 29;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']':
			YYSTAGP(yyt1);
			goto yy336;
		case 0x08: goto yy335;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy337;
		case '#':
		case '/': goto yy16;
		case '&':
			YYSTAGP(yyt1);
			goto yy371;
		default:
			YYSTAGP(yyt1);
			goto yy370;
	}
yy336:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_NODEID];         goto lit; }
yy337:
	yyaccept = 29;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']':
			YYSTAGP(yyt1);
			goto yy336;
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy337;
		case '&':
			YYSTAGP(yyt1);
			goto yy373;
		default:
			YYSTAGP(yyt1);
			goto yy372;
	}
yy338:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy374;
		default: goto yy63;
	}
yy339:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy340;
		default: goto yy63;
	}
yy340:
	yyaccept = 30;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy341;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy340;
		default: goto yy62;
	}
yy341:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_SBYTE];          goto lit; }
yy342:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy343;
		default: goto yy64;
	}
yy343:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy343;
		default: goto yy341;
	}
yy344:
	yyaccept = 31;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy345;
		case 0x08: goto yy344;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy346;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		default: goto yy62;
	}
yy345:
	YYRESTORETAG(yyt1);
	{ tokenId = EF_TOK_SELECT; goto finish; }
yy346:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy346;
		default: goto yy345;
	}
yy347:
	yyaccept = 31;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy345;
		default: goto yy63;
	}
yy348:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'O':
		case 'o': goto yy375;
		default: goto yy63;
	}
yy349:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy349;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy350;
		case '"':
			YYSTAGP(yyt1);
			goto yy376;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '\'':
			YYSTAGP(yyt1);
			goto yy377;
		default: goto yy62;
	}
yy350:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy350;
		case '"':
			YYSTAGP(yyt1);
			goto yy378;
		case '\'':
			YYSTAGP(yyt1);
			goto yy380;
		default: goto yy64;
	}
yy351:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy351;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy352;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy382;
		default: goto yy62;
	}
yy352:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy352;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy384;
		default: goto yy64;
	}
yy353:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy353;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy354;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy385;
		default: goto yy62;
	}
yy354:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy354;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy387;
		default: goto yy64;
	}
yy355:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy355;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy356;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy388;
		default: goto yy62;
	}
yy356:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy356;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy390;
		default: goto yy64;
	}
yy357:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy391;
		default: goto yy63;
	}
yy358:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy392;
		default: goto yy63;
	}
yy359:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy359;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy360;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case 'F':
		case 'f':
			YYSTAGP(yyt1);
			goto yy393;
		case 'T':
		case 't':
			YYSTAGP(yyt1);
			goto yy394;
		default: goto yy62;
	}
yy360:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy360;
		case 'F':
		case 'f':
			YYSTAGP(yyt1);
			goto yy395;
		case 'T':
		case 't':
			YYSTAGP(yyt1);
			goto yy396;
		default: goto yy64;
	}
yy361:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy397;
		default: goto yy63;
	}
yy362:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy398;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy399;
		default: goto yy63;
	}
yy363:
	yyaccept = 32;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy364;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '+':
		case '-':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e': goto yy363;
		case '.': goto yy365;
		default: goto yy62;
	}
yy364:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_DOUBLE];         goto lit; }
yy365:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '+':
		case '-':
		case '.':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'E':
		case 'e': goto yy365;
		default: goto yy364;
	}
yy366:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy400;
		default: goto yy63;
	}
yy367:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'H':
		case 'h': goto yy401;
		default: goto yy63;
	}
yy368:
	yyaccept = 33;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy31;
		case 'O':
		case 'o': goto yy402;
		default: goto yy63;
	}
yy369:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy403;
		default: goto yy63;
	}
yy370:
	yyaccept = 34;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy336;
		case '#':
		case '/': goto yy16;
		case '&': goto yy371;
		default: goto yy370;
	}
yy371:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy370;
	}
yy372:
	yyaccept = 34;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy336;
		case '&': goto yy373;
		default: goto yy372;
	}
yy373:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy372;
	}
yy374:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy404;
		default: goto yy63;
	}
yy375:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy405;
		default: goto yy63;
	}
yy376:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy378;
		case '"': goto yy406;
		case '#':
		case '/': goto yy408;
		case '&': goto yy409;
		case '\\': goto yy410;
		default: goto yy376;
	}
yy377:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy380;
		case '#':
		case '/': goto yy411;
		case '&': goto yy412;
		case '\'': goto yy413;
		case '\\': goto yy415;
		default: goto yy377;
	}
yy378:
	YYSKIP();
	yych = YYPEEK();
yy379:
	switch (yych) {
		case 0x00: goto yy64;
		case '"': goto yy416;
		case '\\': goto yy417;
		default: goto yy378;
	}
yy380:
	YYSKIP();
	yych = YYPEEK();
yy381:
	switch (yych) {
		case 0x00: goto yy64;
		case '\'': goto yy418;
		case '\\': goto yy419;
		default: goto yy380;
	}
yy382:
	yyaccept = 35;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy383;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy382;
		default: goto yy62;
	}
yy383:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_UINT16];         goto lit; }
yy384:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy384;
		default: goto yy383;
	}
yy385:
	yyaccept = 36;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy386;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy385;
		default: goto yy62;
	}
yy386:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_UINT32];         goto lit; }
yy387:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy387;
		default: goto yy386;
	}
yy388:
	yyaccept = 37;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy389;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy388;
		default: goto yy62;
	}
yy389:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_UINT64];         goto lit; }
yy390:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy390;
		default: goto yy389;
	}
yy391:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy420;
		default: goto yy63;
	}
yy392:
	yyaccept = 5;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy61;
		default: goto yy63;
	}
yy393:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy421;
		default: goto yy63;
	}
yy394:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy422;
		default: goto yy63;
	}
yy395:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy423;
		default: goto yy64;
	}
yy396:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy424;
		default: goto yy64;
	}
yy397:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'G':
		case 'g': goto yy425;
		default: goto yy63;
	}
yy398:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy398;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy399;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '-':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z':
			YYSTAGP(yyt1);
			goto yy426;
		case ':':
			YYSTAGP(yyt1);
			goto yy428;
		default: goto yy62;
	}
yy399:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy399;
		case '-':
		case ':':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z':
			YYSTAGP(yyt1);
			goto yy428;
		default: goto yy64;
	}
yy400:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'O':
		case 'o': goto yy429;
		default: goto yy63;
	}
yy401:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy430;
		default: goto yy63;
	}
yy402:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy431;
		default: goto yy63;
	}
yy403:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy432;
		default: goto yy63;
	}
yy404:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy433;
		default: goto yy63;
	}
yy405:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy434;
		default: goto yy63;
	}
yy406:
	yyaccept = 38;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy407;
		default: goto yy63;
	}
yy407:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_STRING];         goto lit; }
yy408:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy378;
		case '"': goto yy435;
		case '&': goto yy436;
		case '[': goto yy437;
		case '\\': goto yy438;
		default: goto yy408;
	}
yy409:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy378;
		case '"': goto yy406;
		case '\\': goto yy410;
		default: goto yy376;
	}
yy410:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy378;
		case '"': goto yy439;
		case '#':
		case '/': goto yy408;
		case '&': goto yy409;
		case '\\': goto yy410;
		default: goto yy376;
	}
yy411:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy380;
		case '&': goto yy440;
		case '\'': goto yy441;
		case '[': goto yy442;
		case '\\': goto yy443;
		default: goto yy411;
	}
yy412:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy380;
		case '\'': goto yy413;
		case '\\': goto yy415;
		default: goto yy377;
	}
yy413:
	yyaccept = 39;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy414;
		default: goto yy63;
	}
yy414:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_STRING];         goto lit; }
yy415:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy380;
		case '#':
		case '/': goto yy411;
		case '&': goto yy412;
		case '\'': goto yy444;
		case '\\': goto yy415;
		default: goto yy377;
	}
yy416:
	YYSKIP();
	goto yy407;
yy417:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '"': goto yy445;
		case '\\': goto yy417;
		default: goto yy378;
	}
yy418:
	YYSKIP();
	goto yy414;
yy419:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\'': goto yy446;
		case '\\': goto yy419;
		default: goto yy380;
	}
yy420:
	yyaccept = 2;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy21;
		default: goto yy63;
	}
yy421:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy447;
		default: goto yy63;
	}
yy422:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy448;
		default: goto yy63;
	}
yy423:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy449;
		default: goto yy64;
	}
yy424:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy450;
		default: goto yy64;
	}
yy425:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy451;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy452;
		default: goto yy63;
	}
yy426:
	yyaccept = 40;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case '[':
		case ']': goto yy427;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '-':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy426;
		case ':': goto yy428;
		default: goto yy62;
	}
yy427:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_DATETIME];       goto lit; }
yy428:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '-':
		case ':':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy428;
		default: goto yy427;
	}
yy429:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy453;
		default: goto yy63;
	}
yy430:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'N':
		case 'n': goto yy454;
		default: goto yy63;
	}
yy431:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy455;
		default: goto yy63;
	}
yy432:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy456;
		default: goto yy63;
	}
yy433:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy457;
		default: goto yy63;
	}
yy434:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy458;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy459;
		default: goto yy63;
	}
yy435:
	yyaccept = 38;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy407;
		default: goto yy17;
	}
yy436:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy378;
		case '"': goto yy435;
		case '\\': goto yy438;
		default: goto yy408;
	}
yy437:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy460;
		default: goto yy379;
	}
yy438:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy378;
		case '"': goto yy461;
		case '&': goto yy436;
		case '[': goto yy437;
		case '\\': goto yy438;
		default: goto yy408;
	}
yy439:
	yyaccept = 38;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy407;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy378;
		case '"': goto yy406;
		case '#':
		case '/': goto yy408;
		case '&': goto yy409;
		case '\\': goto yy410;
		default: goto yy376;
	}
yy440:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\n': goto yy380;
		case '\'': goto yy441;
		case '\\': goto yy443;
		default: goto yy411;
	}
yy441:
	yyaccept = 39;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy414;
		default: goto yy17;
	}
yy442:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy462;
		default: goto yy381;
	}
yy443:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy18;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy380;
		case '&': goto yy440;
		case '\'': goto yy463;
		case '[': goto yy442;
		case '\\': goto yy443;
		default: goto yy411;
	}
yy444:
	yyaccept = 39;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy414;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy380;
		case '#':
		case '/': goto yy411;
		case '&': goto yy412;
		case '\'': goto yy413;
		case '\\': goto yy415;
		default: goto yy377;
	}
yy445:
	yyaccept = 38;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy407;
		case '"': goto yy416;
		case '\\': goto yy417;
		default: goto yy378;
	}
yy446:
	yyaccept = 39;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy414;
		case '\'': goto yy418;
		case '\\': goto yy419;
		default: goto yy380;
	}
yy447:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy448;
		default: goto yy63;
	}
yy448:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy464;
		default: goto yy63;
	}
yy449:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'S':
		case 's': goto yy450;
		default: goto yy64;
	}
yy450:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy466;
		default: goto yy64;
	}
yy451:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy451;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy452;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '=':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z':
			YYSTAGP(yyt1);
			goto yy467;
		default: goto yy62;
	}
yy452:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy452;
		case '=':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z':
			YYSTAGP(yyt1);
			goto yy469;
		default: goto yy64;
	}
yy453:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy470;
		default: goto yy63;
	}
yy454:
	yyaccept = 41;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy34;
		case 'O':
		case 'o': goto yy471;
		default: goto yy63;
	}
yy455:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'Q':
		case 'q': goto yy472;
		default: goto yy63;
	}
yy456:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'X':
		case 'x': goto yy473;
		default: goto yy63;
	}
yy457:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'M':
		case 'm': goto yy474;
		default: goto yy63;
	}
yy458:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy458;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy459;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z':
			YYSTAGP(yyt1);
			goto yy475;
		default: goto yy62;
	}
yy459:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy459;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z':
			YYSTAGP(yyt1);
			goto yy477;
		default: goto yy64;
	}
yy460:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '"': goto yy416;
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy460;
		case '\\': goto yy417;
		case ']': goto yy478;
		default: goto yy378;
	}
yy461:
	yyaccept = 38;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy407;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy378;
		case '"': goto yy435;
		case '&': goto yy436;
		case '[': goto yy437;
		case '\\': goto yy438;
		default: goto yy408;
	}
yy462:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy64;
		case '\'': goto yy418;
		case ',':
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy462;
		case '\\': goto yy419;
		case ']': goto yy479;
		default: goto yy380;
	}
yy463:
	yyaccept = 39;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy414;
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case ']': goto yy380;
		case '&': goto yy440;
		case '\'': goto yy441;
		case '[': goto yy442;
		case '\\': goto yy443;
		default: goto yy411;
	}
yy464:
	yyaccept = 42;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy465;
		default: goto yy63;
	}
yy465:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_BOOLEAN];        goto lit; }
yy466:
	YYSKIP();
	goto yy465;
yy467:
	yyaccept = 43;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy468;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '=':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy467;
		default: goto yy62;
	}
yy468:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_BYTESTRING];     goto lit; }
yy469:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy469;
		default: goto yy468;
	}
yy470:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'I':
		case 'i': goto yy480;
		default: goto yy63;
	}
yy471:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'R':
		case 'r': goto yy481;
		default: goto yy63;
	}
yy472:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy482;
		default: goto yy63;
	}
yy473:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'T':
		case 't': goto yy483;
		default: goto yy63;
	}
yy474:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy484;
		default: goto yy63;
	}
yy475:
	yyaccept = 44;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy476;
		case '#':
		case '/': goto yy16;
		case '&': goto yy65;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy475;
		default: goto yy62;
	}
yy476:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_STATUSCODE];     goto lit; }
yy477:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case 'A':
		case 'B':
		case 'C':
		case 'D':
		case 'E':
		case 'F':
		case 'G':
		case 'H':
		case 'I':
		case 'J':
		case 'K':
		case 'L':
		case 'M':
		case 'N':
		case 'O':
		case 'P':
		case 'Q':
		case 'R':
		case 'S':
		case 'T':
		case 'U':
		case 'V':
		case 'W':
		case 'X':
		case 'Y':
		case 'Z':
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
		case 'h':
		case 'i':
		case 'j':
		case 'k':
		case 'l':
		case 'm':
		case 'n':
		case 'o':
		case 'p':
		case 'q':
		case 'r':
		case 's':
		case 't':
		case 'u':
		case 'v':
		case 'w':
		case 'x':
		case 'y':
		case 'z': goto yy477;
		default: goto yy476;
	}
yy478:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	if (yych <= 0x00) goto yy18;
	goto yy379;
yy479:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	if (yych <= 0x00) goto yy18;
	goto yy381;
yy480:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'D':
		case 'd': goto yy485;
		default: goto yy63;
	}
yy481:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'E':
		case 'e': goto yy486;
		default: goto yy63;
	}
yy482:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy487;
		default: goto yy63;
	}
yy483:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy488;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy489;
		default: goto yy63;
	}
yy484:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy490;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy492;
		default: goto yy63;
	}
yy485:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x08: goto yy493;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy495;
		default: goto yy63;
	}
yy486:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'Q':
		case 'q': goto yy496;
		default: goto yy63;
	}
yy487:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy497;
		default: goto yy63;
	}
yy488:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08: goto yy488;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy489;
		case '#':
		case '/': goto yy16;
		case '&':
			YYSTAGP(yyt1);
			goto yy499;
		case ':':
			YYSTAGP(yyt1);
			goto yy500;
		default:
			YYSTAGP(yyt1);
			goto yy498;
	}
yy489:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy489;
		case '&':
			YYSTAGP(yyt1);
			goto yy503;
		case ':':
			YYSTAGP(yyt1);
			goto yy500;
		default:
			YYSTAGP(yyt1);
			goto yy502;
	}
yy490:
	yyaccept = 45;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']':
			YYSTAGP(yyt1);
			goto yy491;
		case 0x08: goto yy490;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy492;
		case '#':
		case '/': goto yy16;
		case '&':
			YYSTAGP(yyt1);
			goto yy505;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy506;
		default:
			YYSTAGP(yyt1);
			goto yy504;
	}
yy491:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];  goto lit; }
yy492:
	yyaccept = 45;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']':
			YYSTAGP(yyt1);
			goto yy491;
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy492;
		case '&':
			YYSTAGP(yyt1);
			goto yy508;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(yyt1);
			goto yy509;
		default:
			YYSTAGP(yyt1);
			goto yy507;
	}
yy493:
	yyaccept = 46;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']':
			YYSTAGP(yyt1);
			goto yy494;
		case 0x08: goto yy493;
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy495;
		case '#':
		case '/': goto yy16;
		case '&':
			YYSTAGP(yyt1);
			goto yy511;
		default:
			YYSTAGP(yyt1);
			goto yy510;
	}
yy494:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_EXPANDEDNODEID]; goto lit; }
yy495:
	yyaccept = 46;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\f':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']':
			YYSTAGP(yyt1);
			goto yy494;
		case 0x08:
		case '\t':
		case '\n':
		case '\v':
		case '\r':
		case ' ': goto yy495;
		case '&':
			YYSTAGP(yyt1);
			goto yy513;
		default:
			YYSTAGP(yyt1);
			goto yy512;
	}
yy496:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'U':
		case 'u': goto yy514;
		default: goto yy63;
	}
yy497:
	yyaccept = 47;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy94;
		default: goto yy63;
	}
yy498:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case '#':
		case '/': goto yy16;
		case '&': goto yy499;
		case ':': goto yy500;
		default: goto yy498;
	}
yy499:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy498;
	}
yy500:
	yyaccept = 48;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy501;
		case '&': goto yy515;
		default: goto yy500;
	}
yy501:
	b = yyt1;
	{ lt = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];  goto lit; }
yy502:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case '<':
		case '>':
		case '[':
		case ']': goto yy64;
		case '&': goto yy503;
		case ':': goto yy500;
		default: goto yy502;
	}
yy503:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy502;
	}
yy504:
	yyaccept = 49;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy491;
		case '#':
		case '/': goto yy16;
		case '&': goto yy505;
		default: goto yy504;
	}
yy505:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy504;
	}
yy506:
	yyaccept = 49;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case '<':
		case '>':
		case '[':
		case ']': goto yy491;
		case '#':
		case '/': goto yy16;
		case '&': goto yy505;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy506;
		case ':': goto yy507;
		default: goto yy504;
	}
yy507:
	yyaccept = 49;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy491;
		case '&': goto yy508;
		default: goto yy507;
	}
yy508:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy507;
	}
yy509:
	yyaccept = 49;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case '<':
		case '>':
		case '[':
		case ']': goto yy491;
		case '&': goto yy508;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy509;
		default: goto yy507;
	}
yy510:
	yyaccept = 50;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy494;
		case '#':
		case '/': goto yy16;
		case '&': goto yy511;
		default: goto yy510;
	}
yy511:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy510;
	}
yy512:
	yyaccept = 50;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '#':
		case '(':
		case ')':
		case ',':
		case '.':
		case '/':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy494;
		case '&': goto yy513;
		default: goto yy512;
	}
yy513:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy512;
	}
yy514:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'A':
		case 'a': goto yy516;
		default: goto yy63;
	}
yy515:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy64;
		default: goto yy500;
	}
yy516:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'L':
		case 'l': goto yy517;
		default: goto yy63;
	}
yy517:
	yyaccept = 51;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\t':
		case '\n':
		case '\v':
		case '\f':
		case '\r':
		case ' ':
		case '!':
		case '(':
		case ')':
		case ',':
		case '.':
		case ':':
		case '<':
		case '>':
		case '[':
		case ']': goto yy98;
		default: goto yy63;
	}
}

    }

unary_op:
    tokenId = EF_TOK_UNARY_OP;
    goto make_op;

binary_op:
    tokenId = EF_TOK_BINARY_OP;
    goto make_op;

make_op:
    *token = create_operand(ctx, OT_OPERATOR);
    (*token)->operand.op.filter = f;
    goto finish;

namedoperand:
    *token = create_operand(ctx, OT_REF);
    size_t nameSize = (uintptr_t)(pos - b);
    (*token)->operand.ref = (char*)UA_malloc(nameSize+1);
    memcpy((*token)->operand.ref, b, nameSize);
    (*token)->operand.ref[nameSize] = 0;
    tokenId = EF_TOK_NAMEDOPERAND;
    goto finish;

json:
    /* Parse a literal / variant in JSON encoding */
    match.length = (uintptr_t)(end-b);
    match.data = (UA_Byte*)(uintptr_t)b;
    *token = create_operand(ctx, OT_LITERAL);
    UA_DecodeJsonOptions options;
    memset(&options, 0, sizeof(UA_DecodeJsonOptions));
    size_t jsonOffset = 0;
    options.decodedLength = &jsonOffset;
    res = UA_decodeJson(&match, &(*token)->operand.literal,
                        &UA_TYPES[UA_TYPES_VARIANT], &options);
    tokenId = (res == UA_STATUSCODE_GOOD) ? EF_TOK_LITERAL : 0;
    pos = b + jsonOffset;
    goto finish;

lit:
    /* Parse a literal based on the discovered type */
    match.length = (uintptr_t)(pos-b);
    match.data = (UA_Byte*)(uintptr_t)b;
    *token = create_operand(ctx, OT_LITERAL);
    (*token)->operand.literal.data = UA_new(lt);
    (*token)->operand.literal.type = lt;
    if(lt == &UA_TYPES[UA_TYPES_NODEID]) {
        res = UA_NodeId_parse((UA_NodeId*)(*token)->operand.literal.data, match);
    } else if(lt == &UA_TYPES[UA_TYPES_EXPANDEDNODEID]) {
        res = UA_ExpandedNodeId_parse((UA_ExpandedNodeId*)(*token)->operand.literal.data, match);
    } else if(lt == &UA_TYPES[UA_TYPES_GUID]) {
        res = UA_Guid_parse((UA_Guid*)(*token)->operand.literal.data, match);
    } else {
        res = UA_decodeJson(&match, (*token)->operand.literal.data, lt, NULL);
    }
    tokenId = (res == UA_STATUSCODE_GOOD) ? EF_TOK_LITERAL : 0;
    goto finish;

sao:
    /* Parse a SimpleAttributeOperand */
    match.length = (uintptr_t)(pos-b);
    match.data = (UA_Byte*)(uintptr_t)b;
    *token = create_operand(ctx, OT_SAO);
    res = UA_SimpleAttributeOperand_parse(&(*token)->operand.sao, match);
    tokenId = (res == UA_STATUSCODE_GOOD) ? EF_TOK_SAO : 0;

finish:
    if(pos > end)
        pos = end;

    /* Update the offset */
    if(tokenId != 0)
        *offset = (uintptr_t)(pos - content.data);

    return tokenId;
}

/**** amalgamated original file "/src/util/ua_eventfilter_grammar.c" ****/

/* This file is automatically generated by Lemon from input grammar
** source file "ua_eventfilter_grammar.y".
*/
/*
** 2000-05-29
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Driver template for the LEMON parser generator.
**
** The "lemon" program processes an LALR(1) input grammar file, then uses
** this template to construct a parser.  The "lemon" program inserts text
** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
** interstitial "-" characters) contained in this template is changed into
** the value of the %name directive from the grammar.  Otherwise, the content
** of this template is copied straight through into the generate parser
** source file.
**
** The following is the concatenation of all %include directives from the
** input grammar file:
*/
/************ Begin %include sections from the grammar ************************/

#define UA_EventFilterParse_ENGINEALWAYSONSTACK 1
#define NDEBUG 1

/* Declare methods to prevent errors due to missing "static" keyword */
static void UA_EventFilterParseInit(void *);
static void UA_EventFilterParseFinalize(void *p);
int UA_EventFilterParseFallback(int iToken);
static void UA_EventFilterParse(void *yyp, int yymajor, Operand *token, EFParseContext *ctx);
/**************** End of %include directives **********************************/
/* These constants specify the various numeric values for terminal symbols.
***************** Begin token definitions *************************************/
#ifndef EF_TOK_OR
#define EF_TOK_OR                              1
#define EF_TOK_AND                             2
#define EF_TOK_NOT                             3
#define EF_TOK_BINARY_OP                       4
#define EF_TOK_BETWEEN                         5
#define EF_TOK_INLIST                          6
#define EF_TOK_UNARY_OP                        7
#define EF_TOK_SELECT                          8
#define EF_TOK_COMMA                           9
#define EF_TOK_WHERE                          10
#define EF_TOK_SAO                            11
#define EF_TOK_LITERAL                        12
#define EF_TOK_NAMEDOPERAND                   13
#define EF_TOK_LPAREN                         14
#define EF_TOK_RPAREN                         15
#define EF_TOK_LBRACKET                       16
#define EF_TOK_RBRACKET                       17
#define EF_TOK_FOR                            18
#define EF_TOK_COLONEQUAL                     19
#endif
/**************** End token definitions ***************************************/

/* The next sections is a series of control #defines.
** various aspects of the generated parser.
**    YYCODETYPE         is the data type used to store the integer codes
**                       that represent terminal and non-terminal symbols.
**                       "unsigned char" is used if there are fewer than
**                       256 symbols.  Larger types otherwise.
**    YYNOCODE           is a number of type YYCODETYPE that is not used for
**                       any terminal or nonterminal symbol.
**    YYFALLBACK         If defined, this indicates that one or more tokens
**                       (also known as: "terminal symbols") have fall-back
**                       values which should be used if the original symbol
**                       would not parse.  This permits keywords to sometimes
**                       be used as identifiers, for example.
**    YYACTIONTYPE       is the data type used for "action codes" - numbers
**                       that indicate what to do in response to the next
**                       token.
**    UA_EventFilterParseTOKENTYPE     is the data type used for minor type for terminal
**                       symbols.  Background: A "minor type" is a semantic
**                       value associated with a terminal or non-terminal
**                       symbols.  For example, for an "ID" terminal symbol,
**                       the minor type might be the name of the identifier.
**                       Each non-terminal can have a different minor type.
**                       Terminal symbols all have the same minor type, though.
**                       This macros defines the minor type for terminal 
**                       symbols.
**    YYMINORTYPE        is the data type used for all minor types.
**                       This is typically a union of many types, one of
**                       which is UA_EventFilterParseTOKENTYPE.  The entry in the union
**                       for terminal symbols is called "yy0".
**    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
**                       zero the stack is dynamically sized using realloc()
**    UA_EventFilterParseARG_SDECL     A static variable declaration for the %extra_argument
**    UA_EventFilterParseARG_PDECL     A parameter declaration for the %extra_argument
**    UA_EventFilterParseARG_PARAM     Code to pass %extra_argument as a subroutine parameter
**    UA_EventFilterParseARG_STORE     Code to store %extra_argument into yypParser
**    UA_EventFilterParseARG_FETCH     Code to extract %extra_argument from yypParser
**    UA_EventFilterParseCTX_*         As UA_EventFilterParseARG_ except for %extra_context
**    YYERRORSYMBOL      is the code number of the error symbol.  If not
**                       defined, then do no error processing.
**    YYNSTATE           the combined number of states.
**    YYNRULE            the number of rules in the grammar
**    YYNTOKEN           Number of terminal symbols
**    YY_MAX_SHIFT       Maximum value for shift actions
**    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
**    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
**    YY_ERROR_ACTION    The yy_action[] code for syntax error
**    YY_ACCEPT_ACTION   The yy_action[] code for accept
**    YY_NO_ACTION       The yy_action[] code for no-op
**    YY_MIN_REDUCE      Minimum value for reduce actions
**    YY_MAX_REDUCE      Maximum value for reduce actions
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned char
#define YYNOCODE 30
#define YYACTIONTYPE unsigned char
#define UA_EventFilterParseTOKENTYPE  Operand * 
typedef union {
  int yyinit;
  UA_EventFilterParseTOKENTYPE yy0;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define UA_EventFilterParseARG_SDECL  EFParseContext *ctx ;
#define UA_EventFilterParseARG_PDECL , EFParseContext *ctx 
#define UA_EventFilterParseARG_PARAM ,ctx 
#define UA_EventFilterParseARG_FETCH  EFParseContext *ctx =yypParser->ctx ;
#define UA_EventFilterParseARG_STORE yypParser->ctx =ctx ;
#define UA_EventFilterParseCTX_SDECL
#define UA_EventFilterParseCTX_PDECL
#define UA_EventFilterParseCTX_PARAM
#define UA_EventFilterParseCTX_FETCH
#define UA_EventFilterParseCTX_STORE
#define YYNSTATE             37
#define YYNRULE              26
#define YYNRULE_WITH_ACTION  18
#define YYNTOKEN             20
#define YY_MAX_SHIFT         36
#define YY_MIN_SHIFTREDUCE   49
#define YY_MAX_SHIFTREDUCE   74
#define YY_ERROR_ACTION      75
#define YY_ACCEPT_ACTION     76
#define YY_NO_ACTION         77
#define YY_MIN_REDUCE        78
#define YY_MAX_REDUCE        103
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))

/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
** Applications can choose to define yytestcase() in the %include section
** to a macro that can assist in verifying code coverage.  For production
** code the yytestcase() macro should be turned off.  But it is useful
** for testing.
*/
#ifndef yytestcase
# define yytestcase(X)
#endif


/* Next are the tables used to determine what action to take based on the
** current state and lookahead token.  These tables are used to implement
** functions that take a state number and lookahead value and return an
** action integer.  
**
** Suppose the action integer is N.  Then the action is determined as
** follows
**
**   0 <= N <= YY_MAX_SHIFT             Shift N.  That is, push the lookahead
**                                      token onto the stack and goto state N.
**
**   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
**     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
**
**   N == YY_ERROR_ACTION               A syntax error has occurred.
**
**   N == YY_ACCEPT_ACTION              The parser accepts its input.
**
**   N == YY_NO_ACTION                  No such action.  Denotes unused
**                                      slots in the yy_action[] table.
**
**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
**     and YY_MAX_REDUCE
**
** The action table is constructed as a single large table named yy_action[].
** Given state S and lookahead X, the action is computed as either:
**
**    (A)   N = yy_action[ yy_shift_ofst[S] + X ]
**    (B)   N = yy_default[S]
**
** The (A) formula is preferred.  The B formula is used instead if
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X.
**
** The formulas above are for computing the action when the lookahead is
** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
** a reduce action) then the yy_reduce_ofst[] array is used in place of
** the yy_shift_ofst[] array.
**
** The following are the tables generated in this section:
**
**  yy_action[]        A single table containing all actions.
**  yy_lookahead[]     A table containing the lookahead for each entry in
**                     yy_action.  Used to detect hash collisions.
**  yy_shift_ofst[]    For each state, the offset into yy_action for
**                     shifting terminals.
**  yy_reduce_ofst[]   For each state, the offset into yy_action for
**                     shifting non-terminals after a reduce.
**  yy_default[]       Default action for each state.
**
*********** Begin parsing tables **********************************************/
#define YY_ACTTAB_COUNT (92)
static const YYACTIONTYPE yy_action[] = {
 /*     0 */    30,   23,   82,   11,  103,   12,   10,    9,    8,   32,
 /*    10 */    33,   52,   54,   55,   13,   12,   10,    1,    8,   32,
 /*    20 */    33,   63,   36,    6,   34,   12,   10,    5,    8,   32,
 /*    30 */    33,   12,   10,    2,    8,   32,   33,   12,   10,   62,
 /*    40 */     8,   32,   33,   15,   10,   56,    8,   32,   33,   35,
 /*    50 */    35,   21,   82,   94,   21,   82,   31,    8,   32,   33,
 /*    60 */     4,   76,   18,   24,   82,   14,   17,   77,   25,   82,
 /*    70 */    19,   82,   20,   82,   90,   82,   16,   87,   82,   28,
 /*    80 */    82,   29,   82,   27,   82,   22,   82,   26,   82,    7,
 /*    90 */     3,   96,
};
static const YYCODETYPE yy_lookahead[] = {
 /*     0 */    24,   25,   26,    3,   29,    1,    2,    7,    4,    5,
 /*    10 */     6,   11,   12,   13,   14,    1,    2,    8,    4,    5,
 /*    20 */     6,   17,   23,    9,   13,    1,    2,   10,    4,    5,
 /*    30 */     6,    1,    2,    9,    4,    5,    6,    1,    2,   17,
 /*    40 */     4,    5,    6,   18,    2,   15,    4,    5,    6,   28,
 /*    50 */    29,   25,   26,   27,   25,   26,   27,    4,    5,    6,
 /*    60 */     9,   20,   21,   25,   26,   19,   22,   30,   25,   26,
 /*    70 */    25,   26,   25,   26,   25,   26,    9,   25,   26,   25,
 /*    80 */    26,   25,   26,   25,   26,   25,   26,   25,   26,   16,
 /*    90 */    16,    0,   30,   30,   30,   30,   30,   30,   30,   30,
 /*   100 */    30,   30,   30,   30,   30,   30,   30,   30,   30,   30,
 /*   110 */    30,   30,
};
#define YY_SHIFT_COUNT    (36)
#define YY_SHIFT_MIN      (0)
#define YY_SHIFT_MAX      (91)
static const unsigned char yy_shift_ofst[] = {
 /*     0 */     9,    0,    0,    0,    0,    0,    0,    0,    0,    0,
 /*    10 */     0,    0,    0,    0,    0,   11,   11,   25,   17,    4,
 /*    20 */    14,   24,   30,   36,   36,   36,   36,   42,   53,   53,
 /*    30 */    51,   22,   73,   74,   46,   67,   91,
};
#define YY_REDUCE_COUNT (18)
#define YY_REDUCE_MIN   (-25)
#define YY_REDUCE_MAX   (62)
static const signed char yy_reduce_ofst[] = {
 /*     0 */    41,  -24,   26,   29,   38,   43,   45,   47,   49,   52,
 /*    10 */    54,   56,   58,   60,   62,   21,  -25,   -1,   44,
};
static const YYACTIONTYPE yy_default[] = {
 /*     0 */    97,   75,   75,   75,   75,   75,   75,   75,   75,   75,
 /*    10 */    75,   75,   75,   75,   75,   75,   75,  100,   99,   75,
 /*    20 */    75,   93,   75,   78,   79,   80,   95,   88,   89,   86,
 /*    30 */    98,   75,   75,   75,   75,  101,   75,
};
/********** End of lemon-generated parsing tables *****************************/

/* The next table maps tokens (terminal symbols) into fallback tokens.  
** If a construct like the following:
** 
**      %fallback ID X Y Z.
**
** appears in the grammar, then ID becomes a fallback token for X, Y,
** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
** but it does not parse, the type of the token is changed to ID and
** the parse is retried before an error is thrown.
**
** This feature can be used, for example, to cause some keywords in a language
** to revert to identifiers if they keyword does not apply in the context where
** it appears.
*/
#ifdef YYFALLBACK
static const YYCODETYPE yyFallback[] = {
};
#endif /* YYFALLBACK */

/* The following structure represents a single element of the
** parser's stack.  Information stored includes:
**
**   +  The state number for the parser at this level of the stack.
**
**   +  The value of the token stored at this level of the stack.
**      (In other words, the "major" token.)
**
**   +  The semantic value stored at this level of the stack.  This is
**      the information used by the action routines in the grammar.
**      It is sometimes called the "minor" token.
**
** After the "shift" half of a SHIFTREDUCE action, the stateno field
** actually contains the reduce action for the second half of the
** SHIFTREDUCE.
*/
struct yyStackEntry {
  YYACTIONTYPE stateno;  /* The state-number, or reduce action in SHIFTREDUCE */
  YYCODETYPE major;      /* The major token value.  This is the code
                         ** number for the token at this stack level */
  YYMINORTYPE minor;     /* The user-supplied minor token value.  This
                         ** is the value of the token  */
};
typedef struct yyStackEntry yyStackEntry;

/* The state of the parser is completely contained in an instance of
** the following structure */
struct yyParser {
  yyStackEntry *yytos;          /* Pointer to top element of the stack */
#ifdef YYTRACKMAXSTACKDEPTH
  int yyhwm;                    /* High-water mark of the stack */
#endif
#ifndef YYNOERRORRECOVERY
  int yyerrcnt;                 /* Shifts left before out of the error */
#endif
  UA_EventFilterParseARG_SDECL                /* A place to hold %extra_argument */
  UA_EventFilterParseCTX_SDECL                /* A place to hold %extra_context */
#if YYSTACKDEPTH<=0
  int yystksz;                  /* Current side of the stack */
  yyStackEntry *yystack;        /* The parser's stack */
  yyStackEntry yystk0;          /* First stack entry */
#else
  yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
  yyStackEntry *yystackEnd;            /* Last entry in the stack */
#endif
};
typedef struct yyParser yyParser;

#include <assert.h>
#ifndef NDEBUG
#include <stdio.h>
static FILE *yyTraceFILE = 0;
static char *yyTracePrompt = 0;
#endif /* NDEBUG */

#ifndef NDEBUG
/* 
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message.  Tracing is turned off
** by making either argument NULL 
**
** Inputs:
** <ul>
** <li> A FILE* to which trace output should be written.
**      If NULL, then tracing is turned off.
** <li> A prefix string written at the beginning of every
**      line of trace output.  If NULL, then tracing is
**      turned off.
** </ul>
**
** Outputs:
** None.
*/
void UA_EventFilterParseTrace(FILE *TraceFILE, char *zTracePrompt){
  yyTraceFILE = TraceFILE;
  yyTracePrompt = zTracePrompt;
  if( yyTraceFILE==0 ) yyTracePrompt = 0;
  else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
#endif /* NDEBUG */

#if defined(YYCOVERAGE) || !defined(NDEBUG)
/* For tracing shifts, the names of all terminals and nonterminals
** are required.  The following table supplies these names */
static const char *const yyTokenName[] = { 
  /*    0 */ "$",
  /*    1 */ "OR",
  /*    2 */ "AND",
  /*    3 */ "NOT",
  /*    4 */ "BINARY_OP",
  /*    5 */ "BETWEEN",
  /*    6 */ "INLIST",
  /*    7 */ "UNARY_OP",
  /*    8 */ "SELECT",
  /*    9 */ "COMMA",
  /*   10 */ "WHERE",
  /*   11 */ "SAO",
  /*   12 */ "LITERAL",
  /*   13 */ "NAMEDOPERAND",
  /*   14 */ "LPAREN",
  /*   15 */ "RPAREN",
  /*   16 */ "LBRACKET",
  /*   17 */ "RBRACKET",
  /*   18 */ "FOR",
  /*   19 */ "COLONEQUAL",
  /*   20 */ "eventFilter",
  /*   21 */ "selectClause",
  /*   22 */ "whereClause",
  /*   23 */ "forClause",
  /*   24 */ "selectClauseList",
  /*   25 */ "operand",
  /*   26 */ "operator",
  /*   27 */ "operandList",
  /*   28 */ "namedOperandAssignmentList",
  /*   29 */ "namedOperandAssignment",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */

#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
 /*   0 */ "selectClauseList ::= operand",
 /*   1 */ "selectClauseList ::= selectClauseList COMMA operand",
 /*   2 */ "whereClause ::= WHERE operand",
 /*   3 */ "operand ::= SAO",
 /*   4 */ "operand ::= operator",
 /*   5 */ "operand ::= LITERAL",
 /*   6 */ "operand ::= NAMEDOPERAND",
 /*   7 */ "operand ::= LPAREN operand RPAREN",
 /*   8 */ "operator ::= NOT operand",
 /*   9 */ "operator ::= UNARY_OP operand",
 /*  10 */ "operator ::= operand OR operand",
 /*  11 */ "operator ::= operand AND operand",
 /*  12 */ "operator ::= operand BINARY_OP operand",
 /*  13 */ "operator ::= operand INLIST LBRACKET operandList RBRACKET",
 /*  14 */ "operator ::= operand BETWEEN LBRACKET operand COMMA operand RBRACKET",
 /*  15 */ "operandList ::= operand",
 /*  16 */ "operandList ::= operand COMMA operandList",
 /*  17 */ "namedOperandAssignment ::= NAMEDOPERAND COLONEQUAL operand",
 /*  18 */ "eventFilter ::= selectClause whereClause forClause",
 /*  19 */ "selectClause ::=",
 /*  20 */ "selectClause ::= SELECT selectClauseList",
 /*  21 */ "whereClause ::=",
 /*  22 */ "forClause ::=",
 /*  23 */ "forClause ::= FOR namedOperandAssignmentList",
 /*  24 */ "namedOperandAssignmentList ::= namedOperandAssignment",
 /*  25 */ "namedOperandAssignmentList ::= namedOperandAssignmentList COMMA namedOperandAssignment",
};
#endif /* NDEBUG */


#if YYSTACKDEPTH<=0
/*
** Try to increase the size of the parser stack.  Return the number
** of errors.  Return 0 on success.
*/
static int yyGrowStack(yyParser *p){
  int newSize;
  int idx;
  yyStackEntry *pNew;

  newSize = p->yystksz*2 + 100;
  idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
  if( p->yystack==&p->yystk0 ){
    pNew = malloc(newSize*sizeof(pNew[0]));
    if( pNew ) pNew[0] = p->yystk0;
  }else{
    pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
  }
  if( pNew ){
    p->yystack = pNew;
    p->yytos = &p->yystack[idx];
#ifndef NDEBUG
    if( yyTraceFILE ){
      fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
              yyTracePrompt, p->yystksz, newSize);
    }
#endif
    p->yystksz = newSize;
  }
  return pNew==0; 
}
#endif

/* Datatype of the argument to the memory allocated passed as the
** second argument to UA_EventFilterParseAlloc() below.  This can be changed by
** putting an appropriate #define in the %include section of the input
** grammar.
*/
#ifndef YYMALLOCARGTYPE
# define YYMALLOCARGTYPE size_t
#endif

/* Initialize a new parser that has already been allocated.
*/
void UA_EventFilterParseInit(void *yypRawParser UA_EventFilterParseCTX_PDECL){
  yyParser *yypParser = (yyParser*)yypRawParser;
  UA_EventFilterParseCTX_STORE
#ifdef YYTRACKMAXSTACKDEPTH
  yypParser->yyhwm = 0;
#endif
#if YYSTACKDEPTH<=0
  yypParser->yytos = NULL;
  yypParser->yystack = NULL;
  yypParser->yystksz = 0;
  if( yyGrowStack(yypParser) ){
    yypParser->yystack = &yypParser->yystk0;
    yypParser->yystksz = 1;
  }
#endif
#ifndef YYNOERRORRECOVERY
  yypParser->yyerrcnt = -1;
#endif
  yypParser->yytos = yypParser->yystack;
  yypParser->yystack[0].stateno = 0;
  yypParser->yystack[0].major = 0;
#if YYSTACKDEPTH>0
  yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
#endif
}

#ifndef UA_EventFilterParse_ENGINEALWAYSONSTACK
/* 
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
**
** Inputs:
** A pointer to the function used to allocate memory.
**
** Outputs:
** A pointer to a parser.  This pointer is used in subsequent calls
** to UA_EventFilterParse and UA_EventFilterParseFree.
*/
void *UA_EventFilterParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) UA_EventFilterParseCTX_PDECL){
  yyParser *yypParser;
  yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
  if( yypParser ){
    UA_EventFilterParseCTX_STORE
    UA_EventFilterParseInit(yypParser UA_EventFilterParseCTX_PARAM);
  }
  return (void*)yypParser;
}
#endif /* UA_EventFilterParse_ENGINEALWAYSONSTACK */


/* The following function deletes the "minor type" or semantic value
** associated with a symbol.  The symbol can be either a terminal
** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
** a pointer to the value to be deleted.  The code used to do the 
** deletions is derived from the %destructor and/or %token_destructor
** directives of the input grammar.
*/
static void yy_destructor(
  yyParser *yypParser,    /* The parser */
  YYCODETYPE yymajor,     /* Type code for object to destroy */
  YYMINORTYPE *yypminor   /* The object to be destroyed */
){
  UA_EventFilterParseARG_FETCH
  UA_EventFilterParseCTX_FETCH
  switch( yymajor ){
    /* Here is inserted the actions which take place when a
    ** terminal or non-terminal is destroyed.  This can happen
    ** when the symbol is popped from the stack during a
    ** reduce or during error processing or when a parser is 
    ** being destroyed before it is finished parsing.
    **
    ** Note: during a reduce, the only symbols destroyed are those
    ** which appear on the RHS of the rule, but which are *not* used
    ** inside the C code.
    */
/********* Begin destructor definitions ***************************************/
      /* TERMINAL Destructor */
    case 1: /* OR */
    case 2: /* AND */
    case 3: /* NOT */
    case 4: /* BINARY_OP */
    case 5: /* BETWEEN */
    case 6: /* INLIST */
    case 7: /* UNARY_OP */
    case 8: /* SELECT */
    case 9: /* COMMA */
    case 10: /* WHERE */
    case 11: /* SAO */
    case 12: /* LITERAL */
    case 13: /* NAMEDOPERAND */
    case 14: /* LPAREN */
    case 15: /* RPAREN */
    case 16: /* LBRACKET */
    case 17: /* RBRACKET */
    case 18: /* FOR */
    case 19: /* COLONEQUAL */
{
 (void)ctx; 
}
      break;
/********* End destructor definitions *****************************************/
    default:  break;   /* If no destructor action specified: do nothing */
  }
}

/*
** Pop the parser's stack once.
**
** If there is a destructor routine associated with the token which
** is popped from the stack, then call it.
*/
static void yy_pop_parser_stack(yyParser *pParser){
  yyStackEntry *yytos;
  assert( pParser->yytos!=0 );
  assert( pParser->yytos > pParser->yystack );
  yytos = pParser->yytos--;
#ifndef NDEBUG
  if( yyTraceFILE ){
    fprintf(yyTraceFILE,"%sPopping %s\n",
      yyTracePrompt,
      yyTokenName[yytos->major]);
  }
#endif
  yy_destructor(pParser, yytos->major, &yytos->minor);
}

/*
** Clear all secondary memory allocations from the parser
*/
void UA_EventFilterParseFinalize(void *p){
  yyParser *pParser = (yyParser*)p;
  while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
#if YYSTACKDEPTH<=0
  if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
#endif
}

#ifndef UA_EventFilterParse_ENGINEALWAYSONSTACK
/* 
** Deallocate and destroy a parser.  Destructors are called for
** all stack elements before shutting the parser down.
**
** If the YYPARSEFREENEVERNULL macro exists (for example because it
** is defined in a %include section of the input grammar) then it is
** assumed that the input pointer is never NULL.
*/
void UA_EventFilterParseFree(
  void *p,                    /* The parser to be deleted */
  void (*freeProc)(void*)     /* Function used to reclaim memory */
){
#ifndef YYPARSEFREENEVERNULL
  if( p==0 ) return;
#endif
  UA_EventFilterParseFinalize(p);
  (*freeProc)(p);
}
#endif /* UA_EventFilterParse_ENGINEALWAYSONSTACK */

/*
** Return the peak depth of the stack for a parser.
*/
#ifdef YYTRACKMAXSTACKDEPTH
int UA_EventFilterParseStackPeak(void *p){
  yyParser *pParser = (yyParser*)p;
  return pParser->yyhwm;
}
#endif

/* This array of booleans keeps track of the parser statement
** coverage.  The element yycoverage[X][Y] is set when the parser
** is in state X and has a lookahead token Y.  In a well-tested
** systems, every element of this matrix should end up being set.
*/
#if defined(YYCOVERAGE)
static unsigned char yycoverage[YYNSTATE][YYNTOKEN];
#endif

/*
** Write into out a description of every state/lookahead combination that
**
**   (1)  has not been used by the parser, and
**   (2)  is not a syntax error.
**
** Return the number of missed state/lookahead combinations.
*/
#if defined(YYCOVERAGE)
int UA_EventFilterParseCoverage(FILE *out){
  int stateno, iLookAhead, i;
  int nMissed = 0;
  for(stateno=0; stateno<YYNSTATE; stateno++){
    i = yy_shift_ofst[stateno];
    for(iLookAhead=0; iLookAhead<YYNTOKEN; iLookAhead++){
      if( yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
      if( yycoverage[stateno][iLookAhead]==0 ) nMissed++;
      if( out ){
        fprintf(out,"State %d lookahead %s %s\n", stateno,
                yyTokenName[iLookAhead],
                yycoverage[stateno][iLookAhead] ? "ok" : "missed");
      }
    }
  }
  return nMissed;
}
#endif

/*
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
*/
static YYACTIONTYPE yy_find_shift_action(
  YYCODETYPE iLookAhead,    /* The look-ahead token */
  YYACTIONTYPE stateno      /* Current state number */
){
  int i;

  if( stateno>YY_MAX_SHIFT ) return stateno;
  assert( stateno <= YY_SHIFT_COUNT );
#if defined(YYCOVERAGE)
  yycoverage[stateno][iLookAhead] = 1;
#endif
  do{
    i = yy_shift_ofst[stateno];
    assert( i>=0 );
    assert( i<=YY_ACTTAB_COUNT );
    assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD );
    assert( iLookAhead!=YYNOCODE );
    assert( iLookAhead < YYNTOKEN );
    i += iLookAhead;
    assert( i<(int)YY_NLOOKAHEAD );
    if( yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
      YYCODETYPE iFallback;            /* Fallback token */
      assert( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) );
      iFallback = yyFallback[iLookAhead];
      if( iFallback!=0 ){
#ifndef NDEBUG
        if( yyTraceFILE ){
          fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
             yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
        }
#endif
        assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
        iLookAhead = iFallback;
        continue;
      }
#endif
#ifdef YYWILDCARD
      {
        int j = i - iLookAhead + YYWILDCARD;
        assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) );
        if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){
#ifndef NDEBUG
          if( yyTraceFILE ){
            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
               yyTracePrompt, yyTokenName[iLookAhead],
               yyTokenName[YYWILDCARD]);
          }
#endif /* NDEBUG */
          return yy_action[j];
        }
      }
#endif /* YYWILDCARD */
      return yy_default[stateno];
    }else{
      assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) );
      return yy_action[i];
    }
  }while(1);
}

/*
** Find the appropriate action for a parser given the non-terminal
** look-ahead token iLookAhead.
*/
static YYACTIONTYPE yy_find_reduce_action(
  YYACTIONTYPE stateno,     /* Current state number */
  YYCODETYPE iLookAhead     /* The look-ahead token */
){
  int i;
#ifdef YYERRORSYMBOL
  if( stateno>YY_REDUCE_COUNT ){
    return yy_default[stateno];
  }
#else
  assert( stateno<=YY_REDUCE_COUNT );
#endif
  i = yy_reduce_ofst[stateno];
  assert( iLookAhead!=YYNOCODE );
  i += iLookAhead;
#ifdef YYERRORSYMBOL
  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
    return yy_default[stateno];
  }
#else
  assert( i>=0 && i<YY_ACTTAB_COUNT );
  assert( yy_lookahead[i]==iLookAhead );
#endif
  return yy_action[i];
}

/*
** The following routine is called if the stack overflows.
*/
static void yyStackOverflow(yyParser *yypParser){
   UA_EventFilterParseARG_FETCH
   UA_EventFilterParseCTX_FETCH
#ifndef NDEBUG
   if( yyTraceFILE ){
     fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
   }
#endif
   while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
   /* Here code is inserted which will execute if the parser
   ** stack every overflows */
/******** Begin %stack_overflow code ******************************************/
/******** End %stack_overflow code ********************************************/
   UA_EventFilterParseARG_STORE /* Suppress warning about unused %extra_argument var */
   UA_EventFilterParseCTX_STORE
}

/*
** Print tracing information for a SHIFT action
*/
#ifndef NDEBUG
static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){
  if( yyTraceFILE ){
    if( yyNewState<YYNSTATE ){
      fprintf(yyTraceFILE,"%s%s '%s', go to state %d\n",
         yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
         yyNewState);
    }else{
      fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n",
         yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
         yyNewState - YY_MIN_REDUCE);
    }
  }
}
#else
# define yyTraceShift(X,Y,Z)
#endif

/*
** Perform a shift action.
*/
static void yy_shift(
  yyParser *yypParser,          /* The parser to be shifted */
  YYACTIONTYPE yyNewState,      /* The new state to shift in */
  YYCODETYPE yyMajor,           /* The major token to shift in */
  UA_EventFilterParseTOKENTYPE yyMinor        /* The minor token to shift in */
){
  yyStackEntry *yytos;
  yypParser->yytos++;
#ifdef YYTRACKMAXSTACKDEPTH
  if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
    yypParser->yyhwm++;
    assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
  }
#endif
#if YYSTACKDEPTH>0 
  if( yypParser->yytos>yypParser->yystackEnd ){
    yypParser->yytos--;
    yyStackOverflow(yypParser);
    return;
  }
#else
  if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
    if( yyGrowStack(yypParser) ){
      yypParser->yytos--;
      yyStackOverflow(yypParser);
      return;
    }
  }
#endif
  if( yyNewState > YY_MAX_SHIFT ){
    yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
  }
  yytos = yypParser->yytos;
  yytos->stateno = yyNewState;
  yytos->major = yyMajor;
  yytos->minor.yy0 = yyMinor;
  yyTraceShift(yypParser, yyNewState, "Shift");
}

/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
    24,  /* (0) selectClauseList ::= operand */
    24,  /* (1) selectClauseList ::= selectClauseList COMMA operand */
    22,  /* (2) whereClause ::= WHERE operand */
    25,  /* (3) operand ::= SAO */
    25,  /* (4) operand ::= operator */
    25,  /* (5) operand ::= LITERAL */
    25,  /* (6) operand ::= NAMEDOPERAND */
    25,  /* (7) operand ::= LPAREN operand RPAREN */
    26,  /* (8) operator ::= NOT operand */
    26,  /* (9) operator ::= UNARY_OP operand */
    26,  /* (10) operator ::= operand OR operand */
    26,  /* (11) operator ::= operand AND operand */
    26,  /* (12) operator ::= operand BINARY_OP operand */
    26,  /* (13) operator ::= operand INLIST LBRACKET operandList RBRACKET */
    26,  /* (14) operator ::= operand BETWEEN LBRACKET operand COMMA operand RBRACKET */
    27,  /* (15) operandList ::= operand */
    27,  /* (16) operandList ::= operand COMMA operandList */
    29,  /* (17) namedOperandAssignment ::= NAMEDOPERAND COLONEQUAL operand */
    20,  /* (18) eventFilter ::= selectClause whereClause forClause */
    21,  /* (19) selectClause ::= */
    21,  /* (20) selectClause ::= SELECT selectClauseList */
    22,  /* (21) whereClause ::= */
    23,  /* (22) forClause ::= */
    23,  /* (23) forClause ::= FOR namedOperandAssignmentList */
    28,  /* (24) namedOperandAssignmentList ::= namedOperandAssignment */
    28,  /* (25) namedOperandAssignmentList ::= namedOperandAssignmentList COMMA namedOperandAssignment */
};

/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
** of symbols on the right-hand side of that rule. */
static const signed char yyRuleInfoNRhs[] = {
   -1,  /* (0) selectClauseList ::= operand */
   -3,  /* (1) selectClauseList ::= selectClauseList COMMA operand */
   -2,  /* (2) whereClause ::= WHERE operand */
   -1,  /* (3) operand ::= SAO */
   -1,  /* (4) operand ::= operator */
   -1,  /* (5) operand ::= LITERAL */
   -1,  /* (6) operand ::= NAMEDOPERAND */
   -3,  /* (7) operand ::= LPAREN operand RPAREN */
   -2,  /* (8) operator ::= NOT operand */
   -2,  /* (9) operator ::= UNARY_OP operand */
   -3,  /* (10) operator ::= operand OR operand */
   -3,  /* (11) operator ::= operand AND operand */
   -3,  /* (12) operator ::= operand BINARY_OP operand */
   -5,  /* (13) operator ::= operand INLIST LBRACKET operandList RBRACKET */
   -7,  /* (14) operator ::= operand BETWEEN LBRACKET operand COMMA operand RBRACKET */
   -1,  /* (15) operandList ::= operand */
   -3,  /* (16) operandList ::= operand COMMA operandList */
   -3,  /* (17) namedOperandAssignment ::= NAMEDOPERAND COLONEQUAL operand */
   -3,  /* (18) eventFilter ::= selectClause whereClause forClause */
    0,  /* (19) selectClause ::= */
   -2,  /* (20) selectClause ::= SELECT selectClauseList */
    0,  /* (21) whereClause ::= */
    0,  /* (22) forClause ::= */
   -2,  /* (23) forClause ::= FOR namedOperandAssignmentList */
   -1,  /* (24) namedOperandAssignmentList ::= namedOperandAssignment */
   -3,  /* (25) namedOperandAssignmentList ::= namedOperandAssignmentList COMMA namedOperandAssignment */
};

static void yy_accept(yyParser*);  /* Forward Declaration */

/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
**
** The yyLookahead and yyLookaheadToken parameters provide reduce actions
** access to the lookahead token (if any).  The yyLookahead will be YYNOCODE
** if the lookahead token has already been consumed.  As this procedure is
** only called from one place, optimizing compilers will in-line it, which
** means that the extra parameters have no performance impact.
*/
static YYACTIONTYPE yy_reduce(
  yyParser *yypParser,         /* The parser */
  unsigned int yyruleno,       /* Number of the rule by which to reduce */
  int yyLookahead,             /* Lookahead token, or YYNOCODE if none */
  UA_EventFilterParseTOKENTYPE yyLookaheadToken  /* Value of the lookahead token */
  UA_EventFilterParseCTX_PDECL                   /* %extra_context */
){
  int yygoto;                     /* The next state */
  YYACTIONTYPE yyact;             /* The next action */
  yyStackEntry *yymsp;            /* The top of the parser's stack */
  int yysize;                     /* Amount to pop the stack */
  UA_EventFilterParseARG_FETCH
  (void)yyLookahead;
  (void)yyLookaheadToken;
  yymsp = yypParser->yytos;

  switch( yyruleno ){
  /* Beginning here are the reduction cases.  A typical example
  ** follows:
  **   case 0:
  **  #line <lineno> <grammarfile>
  **     { ... }           // User supplied code
  **  #line <lineno> <thisfile>
  **     break;
  */
/********** Begin reduce actions **********************************************/
        YYMINORTYPE yylhsminor;
      case 0: /* selectClauseList ::= operand */
{ append_select(ctx, yymsp[0].minor.yy0); }
        break;
      case 1: /* selectClauseList ::= selectClauseList COMMA operand */
{ append_select(ctx, yymsp[0].minor.yy0); }
  yy_destructor(yypParser,9,&yymsp[-1].minor);
        break;
      case 2: /* whereClause ::= WHERE operand */
{  yy_destructor(yypParser,10,&yymsp[-1].minor);
{ ctx->top = yymsp[0].minor.yy0; }
}
        break;
      case 3: /* operand ::= SAO */
      case 4: /* operand ::= operator */ yytestcase(yyruleno==4);
      case 5: /* operand ::= LITERAL */ yytestcase(yyruleno==5);
      case 6: /* operand ::= NAMEDOPERAND */ yytestcase(yyruleno==6);
      case 15: /* operandList ::= operand */ yytestcase(yyruleno==15);
{ yylhsminor.yy0 = yymsp[0].minor.yy0; }
  yymsp[0].minor.yy0 = yylhsminor.yy0;
        break;
      case 7: /* operand ::= LPAREN operand RPAREN */
{  yy_destructor(yypParser,14,&yymsp[-2].minor);
{ yymsp[-2].minor.yy0 = yymsp[-1].minor.yy0; }
  yy_destructor(yypParser,15,&yymsp[0].minor);
}
        break;
      case 8: /* operator ::= NOT operand */
      case 9: /* operator ::= UNARY_OP operand */ yytestcase(yyruleno==9);
{ yylhsminor.yy0 = yymsp[-1].minor.yy0; append_operand(yylhsminor.yy0, yymsp[0].minor.yy0); }
  yymsp[-1].minor.yy0 = yylhsminor.yy0;
        break;
      case 10: /* operator ::= operand OR operand */
      case 11: /* operator ::= operand AND operand */ yytestcase(yyruleno==11);
      case 12: /* operator ::= operand BINARY_OP operand */ yytestcase(yyruleno==12);
{ yylhsminor.yy0 = yymsp[-1].minor.yy0; append_operand(yylhsminor.yy0, yymsp[-2].minor.yy0), append_operand(yylhsminor.yy0, yymsp[0].minor.yy0); }
  yymsp[-2].minor.yy0 = yylhsminor.yy0;
        break;
      case 13: /* operator ::= operand INLIST LBRACKET operandList RBRACKET */
{ yylhsminor.yy0 = yymsp[-3].minor.yy0; append_operand(yylhsminor.yy0, yymsp[-4].minor.yy0); while(yymsp[-1].minor.yy0) { append_operand(yylhsminor.yy0, yymsp[-1].minor.yy0); yymsp[-1].minor.yy0 = yymsp[-1].minor.yy0->next; } }
  yy_destructor(yypParser,16,&yymsp[-2].minor);
  yy_destructor(yypParser,17,&yymsp[0].minor);
  yymsp[-4].minor.yy0 = yylhsminor.yy0;
        break;
      case 14: /* operator ::= operand BETWEEN LBRACKET operand COMMA operand RBRACKET */
{ yylhsminor.yy0 = yymsp[-5].minor.yy0; append_operand(yylhsminor.yy0, yymsp[-6].minor.yy0); append_operand(yylhsminor.yy0, yymsp[-3].minor.yy0); append_operand(yylhsminor.yy0, yymsp[-1].minor.yy0); }
  yy_destructor(yypParser,16,&yymsp[-4].minor);
  yy_destructor(yypParser,9,&yymsp[-2].minor);
  yy_destructor(yypParser,17,&yymsp[0].minor);
  yymsp[-6].minor.yy0 = yylhsminor.yy0;
        break;
      case 16: /* operandList ::= operand COMMA operandList */
{ yylhsminor.yy0 = yymsp[-2].minor.yy0; yymsp[-2].minor.yy0->next = yymsp[0].minor.yy0; }
  yy_destructor(yypParser,9,&yymsp[-1].minor);
  yymsp[-2].minor.yy0 = yylhsminor.yy0;
        break;
      case 17: /* namedOperandAssignment ::= NAMEDOPERAND COLONEQUAL operand */
{ yymsp[0].minor.yy0->ref = save_string(yymsp[-2].minor.yy0->operand.ref); }
  yy_destructor(yypParser,19,&yymsp[-1].minor);
        break;
      case 20: /* selectClause ::= SELECT selectClauseList */
{  yy_destructor(yypParser,8,&yymsp[-1].minor);
{
}
}
        break;
      case 23: /* forClause ::= FOR namedOperandAssignmentList */
{  yy_destructor(yypParser,18,&yymsp[-1].minor);
{
}
}
        break;
      case 25: /* namedOperandAssignmentList ::= namedOperandAssignmentList COMMA namedOperandAssignment */
{
}
  yy_destructor(yypParser,9,&yymsp[-1].minor);
        break;
      default:
      /* (18) eventFilter ::= selectClause whereClause forClause */ yytestcase(yyruleno==18);
      /* (19) selectClause ::= */ yytestcase(yyruleno==19);
      /* (21) whereClause ::= */ yytestcase(yyruleno==21);
      /* (22) forClause ::= */ yytestcase(yyruleno==22);
      /* (24) namedOperandAssignmentList ::= namedOperandAssignment (OPTIMIZED OUT) */ assert(yyruleno!=24);
        break;
/********** End reduce actions ************************************************/
  }
  assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
  yygoto = yyRuleInfoLhs[yyruleno];
  yysize = yyRuleInfoNRhs[yyruleno];
  yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);

  /* There are no SHIFTREDUCE actions on nonterminals because the table
  ** generator has simplified them to pure REDUCE actions. */
  assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) );

  /* It is not possible for a REDUCE to be followed by an error */
  assert( yyact!=YY_ERROR_ACTION );

  yymsp += yysize+1;
  yypParser->yytos = yymsp;
  yymsp->stateno = (YYACTIONTYPE)yyact;
  yymsp->major = (YYCODETYPE)yygoto;
  yyTraceShift(yypParser, yyact, "... then shift");
  return yyact;
}

/*
** The following code executes when the parse fails
*/
#ifndef YYNOERRORRECOVERY
static void yy_parse_failed(
  yyParser *yypParser           /* The parser */
){
  UA_EventFilterParseARG_FETCH
  UA_EventFilterParseCTX_FETCH
#ifndef NDEBUG
  if( yyTraceFILE ){
    fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
  }
#endif
  while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
  /* Here code is inserted which will be executed whenever the
  ** parser fails */
/************ Begin %parse_failure code ***************************************/
/************ End %parse_failure code *****************************************/
  UA_EventFilterParseARG_STORE /* Suppress warning about unused %extra_argument variable */
  UA_EventFilterParseCTX_STORE
}
#endif /* YYNOERRORRECOVERY */

/*
** The following code executes when a syntax error first occurs.
*/
static void yy_syntax_error(
  yyParser *yypParser,           /* The parser */
  int yymajor,                   /* The major type of the error token */
  UA_EventFilterParseTOKENTYPE yyminor         /* The minor type of the error token */
){
  UA_EventFilterParseARG_FETCH
  UA_EventFilterParseCTX_FETCH
#define TOKEN yyminor
/************ Begin %syntax_error code ****************************************/
 ctx->error = UA_STATUSCODE_BADINTERNALERROR; 
/************ End %syntax_error code ******************************************/
  UA_EventFilterParseARG_STORE /* Suppress warning about unused %extra_argument variable */
  UA_EventFilterParseCTX_STORE
}

/*
** The following is executed when the parser accepts
*/
static void yy_accept(
  yyParser *yypParser           /* The parser */
){
  UA_EventFilterParseARG_FETCH
  UA_EventFilterParseCTX_FETCH
#ifndef NDEBUG
  if( yyTraceFILE ){
    fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
  }
#endif
#ifndef YYNOERRORRECOVERY
  yypParser->yyerrcnt = -1;
#endif
  assert( yypParser->yytos==yypParser->yystack );
  /* Here code is inserted which will be executed whenever the
  ** parser accepts */
/*********** Begin %parse_accept code *****************************************/
/*********** End %parse_accept code *******************************************/
  UA_EventFilterParseARG_STORE /* Suppress warning about unused %extra_argument variable */
  UA_EventFilterParseCTX_STORE
}

/* The main parser program.
** The first argument is a pointer to a structure obtained from
** "UA_EventFilterParseAlloc" which describes the current state of the parser.
** The second argument is the major token number.  The third is
** the minor token.  The fourth optional argument is whatever the
** user wants (and specified in the grammar) and is available for
** use by the action routines.
**
** Inputs:
** <ul>
** <li> A pointer to the parser (an opaque structure.)
** <li> The major token number.
** <li> The minor token number.
** <li> An option argument of a grammar-specified type.
** </ul>
**
** Outputs:
** None.
*/
void UA_EventFilterParse(
  void *yyp,                   /* The parser */
  int yymajor,                 /* The major token code number */
  UA_EventFilterParseTOKENTYPE yyminor       /* The value for the token */
  UA_EventFilterParseARG_PDECL               /* Optional %extra_argument parameter */
){
  YYMINORTYPE yyminorunion;
  YYACTIONTYPE yyact;   /* The parser action. */
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
  int yyendofinput;     /* True if we are at the end of input */
#endif
#ifdef YYERRORSYMBOL
  int yyerrorhit = 0;   /* True if yymajor has invoked an error */
#endif
  yyParser *yypParser = (yyParser*)yyp;  /* The parser */
  UA_EventFilterParseCTX_FETCH
  UA_EventFilterParseARG_STORE

  assert( yypParser->yytos!=0 );
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
  yyendofinput = (yymajor==0);
#endif

  yyact = yypParser->yytos->stateno;
#ifndef NDEBUG
  if( yyTraceFILE ){
    if( yyact < YY_MIN_REDUCE ){
      fprintf(yyTraceFILE,"%sInput '%s' in state %d\n",
              yyTracePrompt,yyTokenName[yymajor],yyact);
    }else{
      fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
              yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE);
    }
  }
#endif

  while(1){ /* Exit by "break" */
    assert( yypParser->yytos>=yypParser->yystack );
    assert( yyact==yypParser->yytos->stateno );
    yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
    if( yyact >= YY_MIN_REDUCE ){
      unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */
#ifndef NDEBUG
      assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
      if( yyTraceFILE ){
        int yysize = yyRuleInfoNRhs[yyruleno];
        if( yysize ){
          fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
            yyTracePrompt,
            yyruleno, yyRuleName[yyruleno],
            yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
            yypParser->yytos[yysize].stateno);
        }else{
          fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
            yyTracePrompt, yyruleno, yyRuleName[yyruleno],
            yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
        }
      }
#endif /* NDEBUG */

      /* Check that the stack is large enough to grow by a single entry
      ** if the RHS of the rule is empty.  This ensures that there is room
      ** enough on the stack to push the LHS value */
      if( yyRuleInfoNRhs[yyruleno]==0 ){
#ifdef YYTRACKMAXSTACKDEPTH
        if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
          yypParser->yyhwm++;
          assert( yypParser->yyhwm ==
                  (int)(yypParser->yytos - yypParser->yystack));
        }
#endif
#if YYSTACKDEPTH>0 
        if( yypParser->yytos>=yypParser->yystackEnd ){
          yyStackOverflow(yypParser);
          break;
        }
#else
        if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
          if( yyGrowStack(yypParser) ){
            yyStackOverflow(yypParser);
            break;
          }
        }
#endif
      }
      yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor UA_EventFilterParseCTX_PARAM);
    }else if( yyact <= YY_MAX_SHIFTREDUCE ){
      yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
#ifndef YYNOERRORRECOVERY
      yypParser->yyerrcnt--;
#endif
      break;
    }else if( yyact==YY_ACCEPT_ACTION ){
      yypParser->yytos--;
      yy_accept(yypParser);
      return;
    }else{
      assert( yyact == YY_ERROR_ACTION );
      yyminorunion.yy0 = yyminor;
#ifdef YYERRORSYMBOL
      int yymx;
#endif
#ifndef NDEBUG
      if( yyTraceFILE ){
        fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
      }
#endif
#ifdef YYERRORSYMBOL
      /* A syntax error has occurred.
      ** The response to an error depends upon whether or not the
      ** grammar defines an error token "ERROR".  
      **
      ** This is what we do if the grammar does define ERROR:
      **
      **  * Call the %syntax_error function.
      **
      **  * Begin popping the stack until we enter a state where
      **    it is legal to shift the error symbol, then shift
      **    the error symbol.
      **
      **  * Set the error count to three.
      **
      **  * Begin accepting and shifting new tokens.  No new error
      **    processing will occur until three tokens have been
      **    shifted successfully.
      **
      */
      if( yypParser->yyerrcnt<0 ){
        yy_syntax_error(yypParser,yymajor,yyminor);
      }
      yymx = yypParser->yytos->major;
      if( yymx==YYERRORSYMBOL || yyerrorhit ){
#ifndef NDEBUG
        if( yyTraceFILE ){
          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
             yyTracePrompt,yyTokenName[yymajor]);
        }
#endif
        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
        yymajor = YYNOCODE;
      }else{
        while( yypParser->yytos > yypParser->yystack ){
          yyact = yy_find_reduce_action(yypParser->yytos->stateno,
                                        YYERRORSYMBOL);
          if( yyact<=YY_MAX_SHIFTREDUCE ) break;
          yy_pop_parser_stack(yypParser);
        }
        if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){
          yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
          yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
          yypParser->yyerrcnt = -1;
#endif
          yymajor = YYNOCODE;
        }else if( yymx!=YYERRORSYMBOL ){
          yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
        }
      }
      yypParser->yyerrcnt = 3;
      yyerrorhit = 1;
      if( yymajor==YYNOCODE ) break;
      yyact = yypParser->yytos->stateno;
#elif defined(YYNOERRORRECOVERY)
      /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
      ** do any kind of error recovery.  Instead, simply invoke the syntax
      ** error routine and continue going as if nothing had happened.
      **
      ** Applications can set this macro (for example inside %include) if
      ** they intend to abandon the parse upon the first syntax error seen.
      */
      yy_syntax_error(yypParser,yymajor, yyminor);
      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
      break;
#else  /* YYERRORSYMBOL is not defined */
      /* This is what we do if the grammar does not define ERROR:
      **
      **  * Report an error message, and throw away the input token.
      **
      **  * If the input token is $, then fail the parse.
      **
      ** As before, subsequent error messages are suppressed until
      ** three input tokens have been successfully shifted.
      */
      if( yypParser->yyerrcnt<=0 ){
        yy_syntax_error(yypParser,yymajor, yyminor);
      }
      yypParser->yyerrcnt = 3;
      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
      if( yyendofinput ){
        yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
        yypParser->yyerrcnt = -1;
#endif
      }
      break;
#endif
    }
  }
#ifndef NDEBUG
  if( yyTraceFILE ){
    yyStackEntry *i;
    char cDiv = '[';
    fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
    for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
      fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
      cDiv = ' ';
    }
    fprintf(yyTraceFILE,"]\n");
  }
#endif
  return;
}

/*
** Return the fallback token corresponding to canonical token iToken, or
** 0 if iToken has no fallback.
*/
int UA_EventFilterParseFallback(int iToken){
#ifdef YYFALLBACK
  assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) );
  return yyFallback[iToken];
#else
  (void)iToken;
  return 0;
#endif
}


/* Main method driving the generated parser from the lexer */
UA_StatusCode
UA_EventFilter_parse(UA_EventFilter *filter, UA_ByteString content,
                     UA_EventFilterParserOptions *options) {
    yyParser parser;
    UA_EventFilterParseInit(&parser);

    EFParseContext ctx;
    memset(&ctx, 0, sizeof(EFParseContext));
    TAILQ_INIT(&ctx.select_operands);
    ctx.logger = (options) ? options->logger : NULL;

    size_t pos = 0;
    unsigned line = 0, col = 0;
    Operand *token = NULL;
    int tokenId = 0;
    UA_StatusCode res;
    do {
        /* Skip whitespace */
        res = UA_EventFilter_skip(content, &pos, &ctx);
        if(res != UA_STATUSCODE_GOOD)
            goto done;

        /* Get the next token */
        size_t begin = pos;
        tokenId = UA_EventFilter_lex(content, &pos, &ctx, &token);
        UA_EventFilterParse(&parser, tokenId, token, &ctx);

        /* Print an error if the parser could not handle the token */
        if(ctx.error != UA_STATUSCODE_GOOD) {
            pos2lines(content, begin, &line, &col);
            int extractLen = 10;
            if(pos - begin < 10)
                extractLen = (int)(pos - begin);
            UA_LOG_ERROR(ctx.logger, UA_LOGCATEGORY_APPLICATION,
                         "Could not process token at line %u, column %u: "
                         "%.*s...", line, col, extractLen, content.data + begin);
            res = UA_STATUSCODE_BADINTERNALERROR;
            goto done;
        }
    } while(tokenId);

    /* Skip trailing whitespace */
    res = UA_EventFilter_skip(content, &pos, &ctx);
    if(res != UA_STATUSCODE_GOOD)
        goto done;

    /* The lexer stopped before the end of the input.
     * The token could not be read. */
    if(pos < content.length) {
        pos2lines(content, pos, &line, &col);
        UA_LOG_ERROR(ctx.logger, UA_LOGCATEGORY_APPLICATION,
                     "Token after the end of the EventFilter expression "
                     "at line %u, column %u", line, col);
        res = UA_STATUSCODE_BADINTERNALERROR;
        goto done;
    }

    /* Create the filter from the parse-tree */
    UA_EventFilter_init(filter);
    res = create_filter(&ctx, filter);

 done:
    UA_EventFilterParseFinalize(&parser);
    EFParseContext_clear(&ctx);
    return res;
}

/**** amalgamated original file "/deps/cj5.c" ****/

// MIT License
//
// Copyright (c) 2020 Sepehr Taghdisian
// Copyright (c) 2022, 2024 Julius Pfrommer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.


#include <math.h>
#include <float.h>
#include <string.h>

#if defined(_MSC_VER)
# define CJ5_INLINE __inline
#else
# define CJ5_INLINE inline
#endif

/* vs2008 does not have INFINITY and NAN defined */
#ifndef INFINITY
# define INFINITY ((double)(DBL_MAX+DBL_MAX))
#endif
#ifndef NAN
# define NAN ((double)(INFINITY-INFINITY))
#endif

#if defined(_MSC_VER)
# pragma warning(disable: 4056)
# pragma warning(disable: 4756)
#endif

/* Max nesting depth of objects and arrays */
#define CJ5_MAX_NESTING 32

#define CJ5__FOURCC(_a, _b, _c, _d)                         \
    (((uint32_t)(_a) | ((uint32_t)(_b) << 8) |              \
      ((uint32_t)(_c) << 16) | ((uint32_t)(_d) << 24)))

static const uint32_t CJ5__NULL_FOURCC  = CJ5__FOURCC('n', 'u', 'l', 'l');
static const uint32_t CJ5__TRUE_FOURCC  = CJ5__FOURCC('t', 'r', 'u', 'e');
static const uint32_t CJ5__FALSE_FOURCC = CJ5__FOURCC('f', 'a', 'l', 's');

typedef struct {
    unsigned int pos;
    cj5_error_code error;

    const char *json5;
    unsigned int len;

    unsigned int curr_tok_idx;

    cj5_token *tokens;
    unsigned int token_count;
    unsigned int max_tokens;

    bool stop_early;
} cj5__parser;

static CJ5_INLINE bool
cj5__isrange(char ch, char from, char to) {
    return (uint8_t)(ch - from) <= (uint8_t)(to - from);
}

#define cj5__isupperchar(ch) cj5__isrange(ch, 'A', 'Z')
#define cj5__islowerchar(ch) cj5__isrange(ch, 'a', 'z')
#define cj5__isnum(ch)       cj5__isrange(ch, '0', '9')

static cj5_token *
cj5__alloc_token(cj5__parser *parser) {
    cj5_token* token = NULL;
    if(parser->token_count < parser->max_tokens) {
        token = &parser->tokens[parser->token_count];
        memset(token, 0x0, sizeof(cj5_token));
    } else {
        parser->error = CJ5_ERROR_OVERFLOW;
    }

    // Always increase the index. So we know eventually how many token would be
    // required (if there are not enough).
    parser->token_count++;
    return token;
}

static void
cj5__parse_string(cj5__parser *parser) {
    const char *json5 = parser->json5;
    unsigned int len = parser->len;
    unsigned int start = parser->pos;
    char str_open = json5[start];

    parser->pos++;
    for(; parser->pos < len; parser->pos++) {
        char c = json5[parser->pos];

        // End of string
        if(str_open == c) {
            cj5_token *token = cj5__alloc_token(parser);
            if(token) {
                token->type = CJ5_TOKEN_STRING;
                token->start = start + 1;
                token->end = parser->pos - 1;
                token->size = token->end - token->start + 1;
                token->parent_id = parser->curr_tok_idx;
            } 
            return;
        }

        // Unescaped newlines are forbidden
        if(c == '\n') {
            parser->error = CJ5_ERROR_INVALID;
            return;
        }

        // Skip escape character
        if(c == '\\') {
            if(parser->pos + 1 >= len) {
                parser->error = CJ5_ERROR_INCOMPLETE;
                return;
            }
            parser->pos++;
        }
    }

    // The file has ended before the string terminates
    parser->error = CJ5_ERROR_INCOMPLETE;
}

// parser->pos is advanced a last time in the next iteration of the main
// parse-loop. So we leave parse-primitive in a state where parse->pos points to
// the last character of the primitive value (or the quote-character of the
// string).
static void
cj5__parse_primitive(cj5__parser* parser) {
    const char* json5 = parser->json5;
    unsigned int len = parser->len;
    unsigned int start = parser->pos;

    // String value
    if(json5[start] == '\"' ||
       json5[start] == '\'') {
        cj5__parse_string(parser);
        return;
    }

    // Fast comparison of bool, and null.
    // Make the comparison case-insensitive.
    uint32_t fourcc = 0;
    if(start + 3 < len) {
        fourcc += (unsigned char)json5[start] | 32U;
        fourcc += ((unsigned char)json5[start+1] | 32U) << 8;
        fourcc += ((unsigned char)json5[start+2] | 32U) << 16;
        fourcc += ((unsigned char)json5[start+3] | 32U) << 24;
    }
    
    cj5_token_type type;
    if(fourcc == CJ5__NULL_FOURCC) {
        type = CJ5_TOKEN_NULL;
        parser->pos += 3;
    } else if(fourcc == CJ5__TRUE_FOURCC) {
        type = CJ5_TOKEN_BOOL;
        parser->pos += 3;
    } else if(fourcc == CJ5__FALSE_FOURCC) {
        // "false" has five characters
        type = CJ5_TOKEN_BOOL;
        if(start + 4 >= len || (json5[start+4] | 32) != 'e') {
            parser->error = CJ5_ERROR_INVALID;
            return;
        }
        parser->pos += 4;
    } else {
        // Numbers are checked for basic compatibility.
        // But they are fully parsed only in the cj5_get_XXX functions.
        type = CJ5_TOKEN_NUMBER;
        for(; parser->pos < len; parser->pos++) {
            if(!cj5__isnum(json5[parser->pos]) &&
               !(json5[parser->pos] == '.') &&
               !cj5__islowerchar(json5[parser->pos]) && 
               !cj5__isupperchar(json5[parser->pos]) &&
               !(json5[parser->pos] == '+') && !(json5[parser->pos] == '-')) {
                break;
            }
        }
        parser->pos--; // Point to the last character that is still inside the
                       // primitive value
    }

    cj5_token *token = cj5__alloc_token(parser);
    if(token) {
        token->type = type;
        token->start = start;
        token->end = parser->pos;
        token->size = parser->pos - start + 1;
        token->parent_id = parser->curr_tok_idx;
    }
}

static void
cj5__parse_key(cj5__parser* parser) {
    const char* json5 = parser->json5;
    unsigned int start = parser->pos;
    cj5_token* token;

    // Key is a a normal string
    if(json5[start] == '\"' || json5[start] == '\'') {
        cj5__parse_string(parser);
        return;
    }

    // An unquoted key. Must start with a-ZA-Z_$. Can contain numbers later on.
    unsigned int len = parser->len;
    for(; parser->pos < len; parser->pos++) {
        if(cj5__islowerchar(json5[parser->pos]) ||
           cj5__isupperchar(json5[parser->pos]) ||
           json5[parser->pos] == '_' || json5[parser->pos] == '$')
            continue;
        if(cj5__isnum(json5[parser->pos]) && parser->pos != start)
            continue;
        break;
    }

    // An empty key is not allowed
    if(parser->pos <= start) {
        parser->error = CJ5_ERROR_INVALID;
        return;
    }

    // Move pos to the last character within the unquoted key
    parser->pos--;

    token = cj5__alloc_token(parser);
    if(token) {
        token->type = CJ5_TOKEN_STRING;
        token->start = start;
        token->end = parser->pos;
        token->size = parser->pos - start + 1;
        token->parent_id = parser->curr_tok_idx;
    }
}

static void
cj5__skip_comment(cj5__parser* parser) {
    const char* json5 = parser->json5;

    // Single-line comment
    if(json5[parser->pos] == '#') {
    skip_line:
        while(parser->pos < parser->len) {
            if(json5[parser->pos] == '\n') {
                parser->pos--; // Reparse the newline in the main parse loop
                return;
            }
            parser->pos++;
        }
        return;
    }

    // Comment begins with '/' but not enough space for another character
    if(parser->pos + 1 >= parser->len) {
        parser->error = CJ5_ERROR_INVALID;
        return;
    }
    parser->pos++;

    // Comment begins with '//' -> single-line comment
    if(json5[parser->pos] == '/')
        goto skip_line;

    // Multi-line comments begin with '/*' and end with '*/'
    if(json5[parser->pos] == '*') {
        parser->pos++;
        for(; parser->pos + 1 < parser->len; parser->pos++) {
            if(json5[parser->pos] == '*' && json5[parser->pos + 1] == '/') {
                parser->pos++;
                return;
            }
        }
    }

    // Unknown comment type or the multi-line comment is not terminated
    parser->error = CJ5_ERROR_INCOMPLETE;
}

cj5_result
cj5_parse(const char *json5, unsigned int len,
          cj5_token *tokens, unsigned int max_tokens,
          cj5_options *options) {
    cj5_result r;
    cj5__parser parser;
    memset(&parser, 0x0, sizeof(parser));
    parser.curr_tok_idx = 0;
    parser.json5 = json5;
    parser.len = len;
    parser.tokens = tokens;
    parser.max_tokens = max_tokens;

    if(options)
        parser.stop_early = options->stop_early;

    unsigned short depth = 0; // Nesting depth zero means "outside the root object"
    char nesting[CJ5_MAX_NESTING]; // Contains either '\0', '{' or '[' for the
                                   // type of nesting at each depth. '\0'
                                   // indicates we are out of the root object.
    char next[CJ5_MAX_NESTING];    // Next content to parse: 'k' (key), ':', 'v'
                                   // (value) or ',' (comma).
    next[0] = 'v';  // The root is a "value" (object, array or primitive). If we
                    // detect a colon after the first value then everything is
                    // wrapped into a "virtual root object" and the parsing is
                    // restarted.
    nesting[0] = 0; // Becomes '{' if there is a virtual root object

    cj5_token *token = NULL; // The current token

 start_parsing:
    for(; parser.pos < len; parser.pos++) {
        char c = json5[parser.pos];
        switch(c) {
        case '\n': // Skip newline and whitespace
        case '\r':
        case '\t':
        case ' ':
            break;

        case '#': // Skip comment
        case '/':
            cj5__skip_comment(&parser);
            if(parser.error != CJ5_ERROR_NONE &&
               parser.error != CJ5_ERROR_OVERFLOW)
                goto finish;
            break;

        case '{': // Open an object or array
        case '[':
            // Check the nesting depth
            if(depth + 1 >= CJ5_MAX_NESTING) {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            // Correct next?
            if(next[depth] != 'v') {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            depth++; // Increase the nesting depth
            nesting[depth] = c; // Set the nesting type
            next[depth] = (c == '{') ? 'k' : 'v'; // next is either a key or a value

            // Create a token for the object or array
            token = cj5__alloc_token(&parser);
            if(token) {
                token->parent_id = parser.curr_tok_idx;
                token->type = (c == '{') ? CJ5_TOKEN_OBJECT : CJ5_TOKEN_ARRAY;
                token->start = parser.pos;
                token->size = 0;
                parser.curr_tok_idx = parser.token_count - 1; // The new curr_tok_idx
                                                              // is for this token
            }
            break;

        case '}': // Close an object or array
        case ']':
            // Check the nesting depth. Note that a "virtual root object" at
            // depth zero must not be closed.
            if(depth == 0) {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            // Check and adjust the nesting. Note that ']' - '[' == 2 and '}' -
            // '{' == 2. Arrays can always be closed. Objects can only close
            // when a key or a comma is expected.
            if(c - nesting[depth] != 2 ||
               (c == '}' && next[depth] != 'k' && next[depth] != ',')) {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            if(token) {
                // Finalize the current token
                token->end = parser.pos;

                // Move to the parent and increase the parent size. Omit this
                // when we leave the root (parent the same as the current
                // token).
                if(parser.curr_tok_idx != token->parent_id) {
                    parser.curr_tok_idx = token->parent_id;
                    token = &tokens[token->parent_id];
                    token->size++;
                }
            }

            // Step one level up
            depth--;
            next[depth] = (depth == 0) ? 0 : ','; // zero if we step out the root
                                                  // object. then we do not look for
                                                  // another element.

            // The first element was successfully parsed. Stop early or try to
            // parse the full input string?
            if(depth == 0 && parser.stop_early)
                goto finish;

            break;

        case ':': // Colon (between key and value)
            if(next[depth] != ':') {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }
            next[depth] = 'v';
            break;

        case ',': // Comma
            if(next[depth] != ',') {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }
            next[depth] = (nesting[depth] == '{') ? 'k' : 'v';
            break;

        default: // Value or key
            if(next[depth] == 'v') {
                cj5__parse_primitive(&parser); // Parse primitive value
                if(nesting[depth] != 0) {
                    // Parent is object or array
                    if(token)
                        token->size++;
                    next[depth] = ',';
                } else {
                    // The current value was the root element. Don't look for
                    // any next element.
                    next[depth] = 0;

                    // The first element was successfully parsed. Stop early or try to
                    // parse the full input string?
                    if(parser.stop_early)
                        goto finish;
                }
            } else if(next[depth] == 'k') {
                cj5__parse_key(&parser);
                if(token)
                    token->size++; // Keys count towards the length
                next[depth] = ':';
            } else {
                parser.error = CJ5_ERROR_INVALID;
            }

            if(parser.error && parser.error != CJ5_ERROR_OVERFLOW)
                goto finish;

            break;
        }
    }

    // Are we back to the initial nesting depth?
    if(depth != 0) {
        parser.error = CJ5_ERROR_INCOMPLETE;
        goto finish;
    }

    // Close the virtual root object if there is one
    if(nesting[0] == '{' && parser.error != CJ5_ERROR_OVERFLOW) {
        // Check the we end after a complete key-value pair (or dangling comma)
        if(next[0] != 'k' && next[0] != ',')
            parser.error = CJ5_ERROR_INVALID;
        tokens[0].end = parser.pos - 1;
    }

 finish:
    // If parsing failed at the initial nesting depth, create a virtual root object
    // and restart parsing.
    if(parser.error != CJ5_ERROR_NONE &&
       parser.error != CJ5_ERROR_OVERFLOW &&
       depth == 0 && nesting[0] != '{') {
        parser.token_count = 0;
        token = cj5__alloc_token(&parser);
        if(token) {
            token->parent_id = 0;
            token->type = CJ5_TOKEN_OBJECT;
            token->start = 0;
            token->size = 0;

            nesting[0] = '{';
            next[0] = 'k';

            parser.curr_tok_idx = 0;
            parser.pos = 0;
            parser.error = CJ5_ERROR_NONE;
            goto start_parsing;
        }
    }

    memset(&r, 0x0, sizeof(r));
    r.error = parser.error;
    r.error_pos = parser.pos;
    r.num_tokens = parser.token_count; // How many tokens (would) have been
                                       // consumed by the parser?

    // Not a single token was parsed -> return an error
    if(r.num_tokens == 0)
        r.error = CJ5_ERROR_INCOMPLETE;

    // Set the tokens and original string only if successfully parsed
    if(r.error == CJ5_ERROR_NONE) {
        r.tokens = tokens;
        r.json5 = json5;
    }

    return r;
}

cj5_error_code
cj5_get_bool(const cj5_result *r, unsigned int tok_index, bool *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_BOOL)
        return CJ5_ERROR_INVALID;
    *out = (r->json5[token->start] == 't');
    return CJ5_ERROR_NONE;
}

cj5_error_code
cj5_get_float(const cj5_result *r, unsigned int tok_index, double *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_NUMBER)
        return CJ5_ERROR_INVALID;

    const char *tokstr = &r->json5[token->start];
    size_t toksize = token->end - token->start + 1;
    if(toksize == 0)
        return CJ5_ERROR_INVALID;

    // Skip prefixed +/-
    bool neg = false;
    if(tokstr[0] == '+' || tokstr[0] == '-') {
        neg = (tokstr[0] == '-');
        tokstr++;
        toksize--;
    }

    // Detect prefixed inf/nan
    if(strncmp(tokstr, "Infinity", toksize) == 0) {
        *out = neg ? -INFINITY : INFINITY;
        return CJ5_ERROR_NONE;
    } else if(strncmp(tokstr, "NaN", toksize) == 0) {
        *out = NAN;
        return CJ5_ERROR_NONE;
    }

    // reset the +/- detection and parse
    tokstr = &r->json5[token->start];
    toksize = token->end - token->start + 1;
    size_t parsed = parseDouble(tokstr, toksize, out);

    // There must only be whitespace between the end of the parsed number and
    // the end of the token
    for(size_t i = parsed; i < toksize; i++) {
        if(tokstr[i] != ' ' && tokstr[i] -'\t' >= 5)
            return CJ5_ERROR_INVALID;
    }

    return (parsed != 0) ? CJ5_ERROR_NONE : CJ5_ERROR_INVALID;
}

cj5_error_code
cj5_get_int(const cj5_result *r, unsigned int tok_index,
            int64_t *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_NUMBER)
        return CJ5_ERROR_INVALID;
    size_t parsed = parseInt64(&r->json5[token->start], token->size, out);
    return (parsed != 0) ? CJ5_ERROR_NONE : CJ5_ERROR_INVALID;
}

cj5_error_code
cj5_get_uint(const cj5_result *r, unsigned int tok_index,
             uint64_t *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_NUMBER)
        return CJ5_ERROR_INVALID;
    size_t parsed = parseUInt64(&r->json5[token->start], token->size, out);
    return (parsed != 0) ? CJ5_ERROR_NONE : CJ5_ERROR_INVALID;
}

static const uint32_t SURROGATE_OFFSET = 0x10000u - (0xD800u << 10) - 0xDC00;

static cj5_error_code
parse_codepoint(const char *pos, uint32_t *out_utf) {
    uint32_t utf = 0;
    for(unsigned int i = 0; i < 4; i++) {
        char byte = pos[i];
        if(cj5__isnum(byte)) {
            byte = (char)(byte - '0');
        } else if(cj5__isrange(byte, 'a', 'f')) {
            byte = (char)(byte - ('a' - 10));
        } else if(cj5__isrange(byte, 'A', 'F')) {
            byte = (char)(byte - ('A' - 10));
        } else {
            return CJ5_ERROR_INVALID;
        }
        utf = (utf << 4) | ((uint8_t)byte & 0xF);
    }
    *out_utf = utf;
    return CJ5_ERROR_NONE;
}

cj5_error_code
cj5_get_str(const cj5_result *r, unsigned int tok_index,
            char *buf, unsigned int *buflen) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_STRING)
        return CJ5_ERROR_INVALID;

    const char *pos = &r->json5[token->start];
    const char *end = &r->json5[token->end + 1];
    unsigned int outpos = 0;
    for(; pos < end; pos++) {
        uint8_t c = (uint8_t)*pos;
        // Unprintable ascii characters must be escaped
        if(c < ' ' || c == 127)
            return CJ5_ERROR_INVALID;

        // Unescaped Ascii character or utf8 byte
        if(c != '\\') {
            buf[outpos++] = (char)c;
            continue;
        }

        // End of input before the escaped character
        if(pos + 1 >= end)
            return CJ5_ERROR_INCOMPLETE;

        // Process escaped character
        pos++;
        c = (uint8_t)*pos;
        switch(c) {
        case 'b': buf[outpos++] = '\b'; break;
        case 'f': buf[outpos++] = '\f'; break;
        case 'r': buf[outpos++] = '\r'; break;
        case 'n': buf[outpos++] = '\n'; break;
        case 't': buf[outpos++] = '\t'; break;
        default:  buf[outpos++] = (char)c; break;
        case 'u': {
            // Parse a unicode code point
            if(pos + 4 >= end)
                return CJ5_ERROR_INCOMPLETE;
            pos++;
            uint32_t utf;
            cj5_error_code err = parse_codepoint(pos, &utf);
            if(err != CJ5_ERROR_NONE)
                return err;
            pos += 3;

            // Parse a surrogate pair
            if(0xd800 <= utf && utf <= 0xdfff) {
                if(pos + 6 >= end)
                    return CJ5_ERROR_INVALID;
                if(pos[1] != '\\' && pos[2] != 'u')
                    return CJ5_ERROR_INVALID;
                pos += 3;
                uint32_t utf2;
                err = parse_codepoint(pos, &utf2);
                if(err != CJ5_ERROR_NONE)
                    return err;
                pos += 3;
                // High or low surrogate pair
                utf = (utf <= 0xdbff) ?
                    (utf << 10) + utf2 + SURROGATE_OFFSET :
                    (utf2 << 10) + utf + SURROGATE_OFFSET;
            }

            // Write the utf8 bytes of the code point
            unsigned len = utf8_from_codepoint((unsigned char*)buf + outpos, utf);
            if(len == 0)
                return CJ5_ERROR_INVALID; // Not a utf8 string
            outpos += len;
            break;
        }
        }
    }

    // Terminate with \0
    buf[outpos] = 0;

    // Set the output length
    if(buflen)
        *buflen = outpos;
    return CJ5_ERROR_NONE;
}

void
cj5_skip(const cj5_result *r, unsigned int *tok_index) {
    unsigned int idx = *tok_index;
    unsigned int end = r->tokens[idx].end;
    do { idx++; } while(idx < r->num_tokens &&
                        r->tokens[idx].start < end);
    *tok_index = idx;
}

cj5_error_code
cj5_find(const cj5_result *r, unsigned int *tok_index,
         const char *key) {
    // It has to be an object
    unsigned int idx = *tok_index;
    if(r->tokens[idx].type != CJ5_TOKEN_OBJECT)
        return CJ5_ERROR_INVALID;
    unsigned int size = r->tokens[idx].size;

    // Skip to the first key
    idx++;

    // Size is number of keys + number of values
    for(unsigned int i = 0; i < size; i += 2) {
        // Key has to be a string
        if(r->tokens[idx].type != CJ5_TOKEN_STRING)
            return CJ5_ERROR_INVALID;

        // Return the index to the value if the key matches
        const char *keystart = &r->json5[r->tokens[idx].start];
        size_t keysize = r->tokens[idx].end - r->tokens[idx].start + 1;
        if(strncmp(key, keystart, keysize) == 0) {
            *tok_index = idx + 1;
            return CJ5_ERROR_NONE;
        }

        // Skip over the value
        idx++;
        cj5_skip(r, &idx);
    }
    return CJ5_ERROR_NOTFOUND;
}

/**** amalgamated original file "/src/ua_types_encoding_json.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Lukas Meling)
 */

/**
 * This file contains the JSON encoding/decoding from before the v1.05 OPC UA
 * specification. The changes in the v1.05 specification are breaking. The
 * encoding is not compatible with new versions. Disable
 * UA_ENABLE_JSON_ENCODING_LEGACY to use the new JSON encoding instead.
 */


#ifdef UA_ENABLE_JSON_ENCODING_LEGACY


#include <float.h>
#include <math.h>


/* vs2008 does not have INFINITY and NAN defined */
#ifndef INFINITY
# define INFINITY ((UA_Double)(DBL_MAX+DBL_MAX))
#endif
#ifndef NAN
# define NAN ((UA_Double)(INFINITY-INFINITY))
#endif

#if defined(_MSC_VER)
# pragma warning(disable: 4756)
# pragma warning(disable: 4056)
#endif

/* Have some slack at the end. E.g. for negative and very long years. */
#define UA_JSON_DATETIME_LENGTH 40

/************/
/* Encoding */
/************/

#define ENCODE_JSON(TYPE) static status \
    TYPE##_encodeJson(CtxJson *ctx, const UA_##TYPE *src, const UA_DataType *type)

#define ENCODE_DIRECT_JSON(SRC, TYPE) \
    TYPE##_encodeJson(ctx, (const UA_##TYPE*)SRC, NULL)

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeChar(CtxJson *ctx, char c) {
    if(ctx->pos >= ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        *ctx->pos = (UA_Byte)c;
    ctx->pos++;
    return UA_STATUSCODE_GOOD;
}

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeChars(CtxJson *ctx, const char *c, size_t len) {
    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        memcpy(ctx->pos, c, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

#define WRITE_JSON_ELEMENT(ELEM)                            \
    UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT status                  \
    writeJson##ELEM(CtxJson *ctx)

static WRITE_JSON_ELEMENT(Quote) {
    return writeChar(ctx, '\"');
}

UA_StatusCode
writeJsonBeforeElement(CtxJson *ctx, UA_Boolean distinct) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    /* Comma if needed */
    if(ctx->commaNeeded[ctx->depth])
        res |= writeChar(ctx, ',');
    if(ctx->prettyPrint) {
        if(distinct) {
            /* Newline and indent if needed */
            res |= writeChar(ctx, '\n');
            for(size_t i = 0; i < ctx->depth; i++)
                res |= writeChar(ctx, '\t');
        } else if(ctx->commaNeeded[ctx->depth]) {
            /* Space after the comma if no newline */
            res |= writeChar(ctx, ' ');
        }
    }
    return res;
}

WRITE_JSON_ELEMENT(ObjStart) {
    /* increase depth, save: before first key-value no comma needed. */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;
    ctx->commaNeeded[ctx->depth] = false;
    return writeChar(ctx, '{');
}

WRITE_JSON_ELEMENT(ObjEnd) {
    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;

    UA_Boolean have_elem = ctx->commaNeeded[ctx->depth];
    ctx->depth--;
    ctx->commaNeeded[ctx->depth] = true;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ctx->prettyPrint && have_elem) {
        res |= writeChar(ctx, '\n');
        for(size_t i = 0; i < ctx->depth; i++)
            res |= writeChar(ctx, '\t');
    }
    return res | writeChar(ctx, '}');
}

WRITE_JSON_ELEMENT(ArrStart) {
    /* increase depth, save: before first array entry no comma needed. */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;
    ctx->commaNeeded[ctx->depth] = false;
    return writeChar(ctx, '[');
}

status
writeJsonArrEnd(CtxJson *ctx, const UA_DataType *type) {
    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    UA_Boolean have_elem = ctx->commaNeeded[ctx->depth];
    ctx->depth--;
    ctx->commaNeeded[ctx->depth] = true;

    /* If the array does not contain JSON objects (with a newline after), then
     * add the closing ] on the same line */
    UA_Boolean distinct = (!type || type->typeKind > UA_DATATYPEKIND_DOUBLE);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ctx->prettyPrint && have_elem && distinct) {
        res |= writeChar(ctx, '\n');
        for(size_t i = 0; i < ctx->depth; i++)
            res |= writeChar(ctx, '\t');
    }
    return res | writeChar(ctx, ']');
}

status
writeJsonArrElm(CtxJson *ctx, const void *value,
                const UA_DataType *type) {
    UA_Boolean distinct = (type->typeKind > UA_DATATYPEKIND_DOUBLE);
    status ret = writeJsonBeforeElement(ctx, distinct);
    ctx->commaNeeded[ctx->depth] = true;
    return ret | encodeJsonJumpTable[type->typeKind](ctx, value, type);
}

status
writeJsonObjElm(CtxJson *ctx, const char *key,
                const void *value, const UA_DataType *type) {
    status ret = writeJsonKey(ctx, key);
    return ret | encodeJsonJumpTable[type->typeKind](ctx, value, type);
}

/* Keys for JSON */

/* LocalizedText */
static const char* UA_JSONKEY_LOCALE = "Locale";
static const char* UA_JSONKEY_TEXT = "Text";

/* QualifiedName */
static const char* UA_JSONKEY_NAME = "Name";
static const char* UA_JSONKEY_URI = "Uri";

/* NodeId */
static const char* UA_JSONKEY_ID = "Id";
static const char* UA_JSONKEY_IDTYPE = "IdType";
static const char* UA_JSONKEY_NAMESPACE = "Namespace";

/* ExpandedNodeId */
static const char* UA_JSONKEY_SERVERURI = "ServerUri";

/* Variant */
static const char* UA_JSONKEY_TYPE = "Type";
static const char* UA_JSONKEY_BODY = "Body";
static const char* UA_JSONKEY_DIMENSION = "Dimension";

/* DataValue */
static const char* UA_JSONKEY_VALUE = "Value";
static const char* UA_JSONKEY_STATUS = "Status";
static const char* UA_JSONKEY_SOURCETIMESTAMP = "SourceTimestamp";
static const char* UA_JSONKEY_SOURCEPICOSECONDS = "SourcePicoseconds";
static const char* UA_JSONKEY_SERVERTIMESTAMP = "ServerTimestamp";
static const char* UA_JSONKEY_SERVERPICOSECONDS = "ServerPicoseconds";

/* ExtensionObject */
static const char* UA_JSONKEY_ENCODING = "Encoding";
static const char* UA_JSONKEY_TYPEID = "TypeId";

/* StatusCode */
static const char* UA_JSONKEY_CODE = "Code";
static const char* UA_JSONKEY_SYMBOL = "Symbol";

/* DiagnosticInfo */
static const char* UA_JSONKEY_SYMBOLICID = "SymbolicId";
static const char* UA_JSONKEY_NAMESPACEURI = "NamespaceUri";
static const char* UA_JSONKEY_LOCALIZEDTEXT = "LocalizedText";
static const char* UA_JSONKEY_ADDITIONALINFO = "AdditionalInfo";
static const char* UA_JSONKEY_INNERSTATUSCODE = "InnerStatusCode";
static const char* UA_JSONKEY_INNERDIAGNOSTICINFO = "InnerDiagnosticInfo";

/* Writes null terminated string to output buffer (current ctx->pos). Writes
 * comma in front of key if needed. Encapsulates key in quotes. */
status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeJsonKey(CtxJson *ctx, const char* key) {
    status ret = writeJsonBeforeElement(ctx, true);
    ctx->commaNeeded[ctx->depth] = true;
    if(!ctx->unquotedKeys)
        ret |= writeChar(ctx, '\"');
    ret |= writeChars(ctx, key, strlen(key));
    if(!ctx->unquotedKeys)
        ret |= writeChar(ctx, '\"');
    ret |= writeChar(ctx, ':');
    if(ctx->prettyPrint)
        ret |= writeChar(ctx, ' ');
    return ret;
}

static bool
isNull(const void *p, const UA_DataType *type) {
    if(UA_DataType_isNumeric(type) || type->typeKind == UA_DATATYPEKIND_BOOLEAN)
        return false;
    UA_STACKARRAY(char, buf, type->memSize);
    memset(buf, 0, type->memSize);
    return UA_equal(buf, p, type);
}

/* Boolean */
ENCODE_JSON(Boolean) {
    if(*src == true)
        return writeChars(ctx, "true", 4);
    return writeChars(ctx, "false", 5);
}

/* Byte */
ENCODE_JSON(Byte) {
    char buf[4];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    /* Ensure destination can hold the data- */
    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    /* Copy digits to the output string/buffer. */
    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* signed Byte */
ENCODE_JSON(SByte) {
    char buf[5];
    UA_UInt16 digits = itoaSigned(*src, buf);
    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt16 */
ENCODE_JSON(UInt16) {
    char buf[6];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* Int16 */
ENCODE_JSON(Int16) {
    char buf[7];
    UA_UInt16 digits = itoaSigned(*src, buf);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt32 */
ENCODE_JSON(UInt32) {
    char buf[11];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* Int32 */
ENCODE_JSON(Int32) {
    char buf[12];
    UA_UInt16 digits = itoaSigned(*src, buf);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt64 */
ENCODE_JSON(UInt64) {
    char buf[23];
    buf[0] = '\"';
    UA_UInt16 digits = itoaUnsigned(*src, buf + 1, 10);
    buf[digits + 1] = '\"';
    UA_UInt16 length = (UA_UInt16)(digits + 2);

    if(ctx->pos + length > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, length);
    ctx->pos += length;
    return UA_STATUSCODE_GOOD;
}

/* Int64 */
ENCODE_JSON(Int64) {
    char buf[23];
    buf[0] = '\"';
    UA_UInt16 digits = itoaSigned(*src, buf + 1);
    buf[digits + 1] = '\"';
    UA_UInt16 length = (UA_UInt16)(digits + 2);

    if(ctx->pos + length > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, length);
    ctx->pos += length;
    return UA_STATUSCODE_GOOD;
}

ENCODE_JSON(Float) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "\"NaN\"");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "\"Infinity\"");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "\"-Infinity\"");
        len = strlen(buffer);
    } else {
        len = dtoa((UA_Double)*src, buffer);
    }

    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buffer, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

ENCODE_JSON(Double) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "\"NaN\"");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "\"Infinity\"");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "\"-Infinity\"");
        len = strlen(buffer);
    } else {
        len = dtoa(*src, buffer);
    }

    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buffer, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

static status
encodeJsonArray(CtxJson *ctx, const void *ptr, size_t length,
                const UA_DataType *type) {
    /* Null-arrays (length -1) are written as empty arrays '[]'.
     * TODO: Clarify the difference between length -1 and length 0 in JSON. */
    status ret = writeJsonArrStart(ctx);
    if(!ptr)
        return ret | writeJsonArrEnd(ctx, type);

    uintptr_t uptr = (uintptr_t)ptr;
    encodeJsonSignature encodeType = encodeJsonJumpTable[type->typeKind];
    UA_Boolean distinct = (type->typeKind > UA_DATATYPEKIND_DOUBLE);
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) {
        ret |= writeJsonBeforeElement(ctx, distinct);
        if(isNull((const void*)uptr, type))
            ret |= writeChars(ctx, "null", 4);
        else
            ret |= encodeType(ctx, (const void*)uptr, type);
        ctx->commaNeeded[ctx->depth] = true;
        uptr += type->memSize;
    }
    return ret | writeJsonArrEnd(ctx, type);
}

static const u8 hexmap[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

ENCODE_JSON(String) {
    if(!src->data)
        return writeChars(ctx, "null", 4);

    status ret = UA_STATUSCODE_GOOD;
    if(src->length == 0) {
        ret |= writeJsonQuote(ctx);
        ret |= writeJsonQuote(ctx);
        return ret;
    }

    ret |= writeJsonQuote(ctx);

    const unsigned char *end = src->data + src->length;
    for(const unsigned char *pos = src->data; pos < end; pos++) {
        /* Skip to the first character that needs escaping */
        const unsigned char *start = pos;
        for(; pos < end; pos++) {
            if(*pos < ' ' || *pos == 127 || *pos == '\\' || *pos == '\"')
                break;
        }

        /* Write out the unescaped sequence */
        if(ctx->pos + (pos - start) > ctx->end)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        if(!ctx->calcOnly)
            memcpy(ctx->pos, start, (size_t)(pos - start));
        ctx->pos += pos - start;

        /* The unescaped sequence reached the end */
        if(pos == end)
            break;

        /* Write an escaped character */
        char *escape_text;
        char escape_buf[6];
        size_t escape_len = 2;
        switch(*pos) {
        case '\b': escape_text = "\\b"; break;
        case '\f': escape_text = "\\f"; break;
        case '\n': escape_text = "\\n"; break;
        case '\r': escape_text = "\\r"; break;
        case '\t': escape_text = "\\t"; break;
        default:
            escape_text = escape_buf;
            if(*pos >= ' ' && *pos != 127) {
                /* Escape \ or " */
                escape_buf[0] = '\\';
                escape_buf[1] = *pos;
            } else {
                /* Unprintable characters need to be escaped */
                escape_buf[0] = '\\';
                escape_buf[1] = 'u';
                escape_buf[2] = '0';
                escape_buf[3] = '0';
                escape_buf[4] = hexmap[*pos >> 4];
                escape_buf[5] = hexmap[*pos & 0x0f];
                escape_len = 6;
            }
            break;
        }

        /* Enough space? */
        if(ctx->pos + escape_len > ctx->end)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

        /* Write the escaped character */
        if(!ctx->calcOnly)
            memcpy(ctx->pos, escape_text, escape_len);
        ctx->pos += escape_len;
    }

    return ret | writeJsonQuote(ctx);
}

ENCODE_JSON(ByteString) {
    if(!src->data)
        return writeChars(ctx, "null", 4);

    if(src->length == 0) {
        status retval = writeJsonQuote(ctx);
        retval |= writeJsonQuote(ctx);
        return retval;
    }

    status ret = writeJsonQuote(ctx);
    size_t flen = 0;
    unsigned char *ba64 = UA_base64(src->data, src->length, &flen);

    /* Not converted, no mem */
    if(!ba64)
        return UA_STATUSCODE_BADENCODINGERROR;

    if(ctx->pos + flen > ctx->end) {
        UA_free(ba64);
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    }

    /* Copy flen bytes to output stream. */
    if(!ctx->calcOnly)
        memcpy(ctx->pos, ba64, flen);
    ctx->pos += flen;

    /* Base64 result no longer needed */
    UA_free(ba64);

    return ret | writeJsonQuote(ctx);
}

/* Guid */
ENCODE_JSON(Guid) {
    if(ctx->pos + 38 > ctx->end) /* 36 + 2 (") */
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    status ret = writeJsonQuote(ctx);
    if(!ctx->calcOnly)
        UA_Guid_to_hex(src, ctx->pos, false);
    ctx->pos += 36;
    return ret | writeJsonQuote(ctx);
}

static u8
printNumber(i32 n, char *pos, u8 min_digits) {
    char digits[10];
    u8 len = 0;
    /* Handle negative values */
    if(n < 0) {
        pos[len++] = '-';
        n = -n;
    }

    /* Extract the digits */
    u8 i = 0;
    for(; i < min_digits || n > 0; i++) {
        digits[i] = (char)((n % 10) + '0');
        n /= 10;
    }

    /* Print in reverse order and return */
    for(; i > 0; i--)
        pos[len++] = digits[i-1];
    return len;
}

ENCODE_JSON(DateTime) {
    UA_DateTimeStruct tSt = UA_DateTime_toStruct(*src);

    /* Format: -yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z' is used. max 31 bytes.
     * Note the optional minus for negative years. */
    char buffer[UA_JSON_DATETIME_LENGTH];
    char *pos = buffer;
    pos += printNumber(tSt.year, pos, 4);
    *(pos++) = '-';
    pos += printNumber(tSt.month, pos, 2);
    *(pos++) = '-';
    pos += printNumber(tSt.day, pos, 2);
    *(pos++) = 'T';
    pos += printNumber(tSt.hour, pos, 2);
    *(pos++) = ':';
    pos += printNumber(tSt.min, pos, 2);
    *(pos++) = ':';
    pos += printNumber(tSt.sec, pos, 2);
    *(pos++) = '.';
    pos += printNumber(tSt.milliSec, pos, 3);
    pos += printNumber(tSt.microSec, pos, 3);
    pos += printNumber(tSt.nanoSec, pos, 3);

    UA_assert(pos <= &buffer[UA_JSON_DATETIME_LENGTH]);

    /* Remove trailing zeros */
    pos--;
    while(*pos == '0')
        pos--;
    if(*pos == '.')
        pos--;

    *(++pos) = 'Z';
    UA_String str = {((uintptr_t)pos - (uintptr_t)buffer)+1, (UA_Byte*)buffer};
    return ENCODE_DIRECT_JSON(&str, String);
}

/* NodeId */
static status
NodeId_encodeJsonInternal(CtxJson *ctx, UA_NodeId const *src) {
    status ret = UA_STATUSCODE_GOOD;
    switch(src->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID);
        ret |= ENCODE_DIRECT_JSON(&src->identifier.numeric, UInt32);
        break;
    case UA_NODEIDTYPE_STRING:
        ret |= writeJsonKey(ctx, UA_JSONKEY_IDTYPE);
        ret |= writeChar(ctx, '1');
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID);
        ret |= ENCODE_DIRECT_JSON(&src->identifier.string, String);
        break;
    case UA_NODEIDTYPE_GUID:
        ret |= writeJsonKey(ctx, UA_JSONKEY_IDTYPE);
        ret |= writeChar(ctx, '2');
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID); /* Id */
        ret |= ENCODE_DIRECT_JSON(&src->identifier.guid, Guid);
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        ret |= writeJsonKey(ctx, UA_JSONKEY_IDTYPE);
        ret |= writeChar(ctx, '3');
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID); /* Id */
        ret |= ENCODE_DIRECT_JSON(&src->identifier.byteString, ByteString);
        break;
    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return ret;
}

ENCODE_JSON(NodeId) {
    /* Encode as string (non-standard). Encode with the standard utf8 escaping.
     * As the NodeId can contain quote characters, etc. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(ctx->stringNodeIds) {
        UA_String out = UA_STRING_NULL;
        ret |= UA_NodeId_print(src, &out);
        ret |= ENCODE_DIRECT_JSON(&out, String);
        UA_String_clear(&out);
        return ret;
    }

    /* Encode as object */
    ret |= writeJsonObjStart(ctx);
    ret |= NodeId_encodeJsonInternal(ctx, src);
    if(ctx->useReversible) {
        if(src->namespaceIndex > 0) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        }
    } else {
        /* For the non-reversible encoding, the field is the NamespaceUri
         * associated with the NamespaceIndex, encoded as a JSON string.
         * A NamespaceIndex of 1 is always encoded as a JSON number. */
        ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
        if(src->namespaceIndex == 1) {
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        } else {
            /* Check if Namespace given and in range */
            UA_String nsUri = UA_STRING_NULL;
            UA_UInt16 ns = src->namespaceIndex;
            if(ctx->namespaceMapping)
                UA_NamespaceMapping_index2Uri(ctx->namespaceMapping, ns, &nsUri);
            if(nsUri.length > 0) {
                ret |= ENCODE_DIRECT_JSON(&nsUri, String);
            } else {
                /* If not found, print the identifier */
                ret |= ENCODE_DIRECT_JSON(&ns, UInt16);
            }
        }
    }

    return ret | writeJsonObjEnd(ctx);
}

/* ExpandedNodeId */
ENCODE_JSON(ExpandedNodeId) {
    /* Encode as string (non-standard). Encode with utf8 escaping as the NodeId
     * can contain quote characters, etc. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(ctx->stringNodeIds) {
        UA_String out = UA_STRING_NULL;
        ret |= UA_ExpandedNodeId_print(src, &out);
        ret |= ENCODE_DIRECT_JSON(&out, String);
        UA_String_clear(&out);
        return ret;
    }

    /* Encode as object */
    ret |= writeJsonObjStart(ctx);

    /* Encode the identifier portion */
    ret |= NodeId_encodeJsonInternal(ctx, &src->nodeId);

    if(ctx->useReversible) {
        /* Reversible Case */

        if(src->namespaceUri.data) {
            /* If the NamespaceUri is specified it is encoded as a JSON string
             * in this field */
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceUri, String);
        } else if(src->nodeId.namespaceIndex > 0) {
            /* If the NamespaceUri is not specified, the NamespaceIndex is
             * encoded. Encoded as a JSON number for the reversible encoding.
             * Omitted if the NamespaceIndex equals 0. */
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->nodeId.namespaceIndex, UInt16);
        }

        /* Encode the serverIndex/Url. As a JSON number for the reversible
         * encoding. Omitted if the ServerIndex equals 0. */
        if(src->serverIndex > 0) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERURI);
            ret |= ENCODE_DIRECT_JSON(&src->serverIndex, UInt32);
        }
    } else {
        /* Non-Reversible Case */

        /* If the NamespaceUri is not specified, the NamespaceIndex is encoded
         * with these rules: For the non-reversible encoding the field is the
         * NamespaceUri associated with the NamespaceIndex encoded as a JSON
         * string. A NamespaceIndex of 1 is always encoded as a JSON number. */

        ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
        if(src->namespaceUri.data) {
            ret |= ENCODE_DIRECT_JSON(&src->namespaceUri, String);
        } else {
            if(src->nodeId.namespaceIndex == 1) {
                ret |= ENCODE_DIRECT_JSON(&src->nodeId.namespaceIndex, UInt16);
            } else {
                /* Check if Namespace given and in range */
                UA_String nsUri = UA_STRING_NULL;
                UA_UInt16 ns = src->nodeId.namespaceIndex;
                if(ctx->namespaceMapping)
                    UA_NamespaceMapping_index2Uri(ctx->namespaceMapping, ns, &nsUri);
                if(nsUri.length > 0) {
                    ret |= ENCODE_DIRECT_JSON(&nsUri, String);
                } else {
                    ret |= ENCODE_DIRECT_JSON(&ns, UInt16);
                }
            }
        }

        /* For the non-reversible encoding, this field is the ServerUri
         * associated with the ServerIndex portion of the ExpandedNodeId,
         * encoded as a JSON string. */

        /* Check if server given and in range */
        if(src->serverIndex >= ctx->serverUrisSize || !ctx->serverUris)
            return UA_STATUSCODE_BADNOTFOUND;

        UA_String serverUriEntry = ctx->serverUris[src->serverIndex];
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERURI);
        ret |= ENCODE_DIRECT_JSON(&serverUriEntry, String);
    }

    return ret | writeJsonObjEnd(ctx);
}

/* LocalizedText */
ENCODE_JSON(LocalizedText) {
    if(ctx->useReversible) {
        status ret = writeJsonObjStart(ctx);
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALE);
        ret |= ENCODE_DIRECT_JSON(&src->locale, String);
        ret |= writeJsonKey(ctx, UA_JSONKEY_TEXT);
        ret |= ENCODE_DIRECT_JSON(&src->text, String);
        return ret | writeJsonObjEnd(ctx);
    }

    /* For the non-reversible form, LocalizedText value shall be encoded as a
     * JSON string containing the Text component.*/
    return ENCODE_DIRECT_JSON(&src->text, String);
}

ENCODE_JSON(QualifiedName) {
    status ret = writeJsonObjStart(ctx);
    ret |= writeJsonKey(ctx, UA_JSONKEY_NAME);
    ret |= ENCODE_DIRECT_JSON(&src->name, String);

    if(ctx->useReversible) {
        if(src->namespaceIndex != 0) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_URI);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        }
    } else {
        /* For the non-reversible form, the NamespaceUri associated with the
         * NamespaceIndex portion of the QualifiedName is encoded as JSON string
         * unless the NamespaceIndex is 1 or if NamespaceUri is unknown. In
         * these cases, the NamespaceIndex is encoded as a JSON number. */
        ret |= writeJsonKey(ctx, UA_JSONKEY_URI);
        if(src->namespaceIndex == 1) {
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        } else {
            /* Check if Namespace given and in range */
            UA_String nsUri = UA_STRING_NULL;
            UA_UInt16 ns = src->namespaceIndex;
            if(ctx->namespaceMapping)
                UA_NamespaceMapping_index2Uri(ctx->namespaceMapping, ns, &nsUri);
            if(nsUri.length > 0) {
                ret |= ENCODE_DIRECT_JSON(&nsUri, String);
            } else {
                ret |= ENCODE_DIRECT_JSON(&ns, UInt16); /* If not encode as number */
            }
        }
    }

    return ret | writeJsonObjEnd(ctx);
}

ENCODE_JSON(StatusCode) {
    if(ctx->useReversible)
        return ENCODE_DIRECT_JSON(src, UInt32);

    const char *codename = UA_StatusCode_name(*src);
    UA_String statusDescription = UA_STRING((char*)(uintptr_t)codename);

    status ret = UA_STATUSCODE_GOOD;
    ret |= writeJsonObjStart(ctx);
    ret |= writeJsonKey(ctx, UA_JSONKEY_CODE);
    ret |= ENCODE_DIRECT_JSON(src, UInt32);
    ret |= writeJsonKey(ctx, UA_JSONKEY_SYMBOL);
    ret |= ENCODE_DIRECT_JSON(&statusDescription, String);
    ret |= writeJsonObjEnd(ctx);
    return ret;
}

/* ExtensionObject */
ENCODE_JSON(ExtensionObject) {
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return writeChars(ctx, "null", 4);

    /* Must have a type set if data is decoded */
    if(src->encoding >= UA_EXTENSIONOBJECT_DECODED && !src->content.decoded.type)
        return UA_STATUSCODE_BADENCODINGERROR;

    status ret = writeJsonObjStart(ctx);

    /* Reversible encoding */
    if(ctx->useReversible) {
        /* Write the type NodeId */
        ret |= writeJsonKey(ctx, UA_JSONKEY_TYPEID);
        if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING ||
           src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML)
            ret |= ENCODE_DIRECT_JSON(&src->content.encoded.typeId, NodeId);
        else
            ret |= ENCODE_DIRECT_JSON(&src->content.decoded.type->typeId, NodeId);

        /* Write the encoding */
        if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_ENCODING);
            ret |= writeChar(ctx, '1');
        } else if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_ENCODING);
            ret |= writeChar(ctx, '2');
        }
    }

    /* Write the body */
    ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING ||
       src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML) {
        ret |= ENCODE_DIRECT_JSON(&src->content.encoded.body, String);
    } else {
        const UA_DataType *t = src->content.decoded.type;
        ret |= encodeJsonJumpTable[t->typeKind]
            (ctx, src->content.decoded.data, t);
    }

    return ret | writeJsonObjEnd(ctx);
}

/* Non-builtin types get wrapped in an ExtensionObject */
static status
encodeScalarJsonWrapExtensionObject(CtxJson *ctx, const UA_Variant *src) {
    const UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    const void *ptr = src->data;
    const UA_DataType *type = src->type;

    /* Set up a temporary ExtensionObject to wrap the data */
    UA_ExtensionObject eo;
    if(!isBuiltin) {
        UA_ExtensionObject_init(&eo);
        eo.encoding = UA_EXTENSIONOBJECT_DECODED;
        eo.content.decoded.type = src->type;
        eo.content.decoded.data = src->data;
        ptr = &eo;
        type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
    }

    return encodeJsonJumpTable[type->typeKind](ctx, ptr, type);
}

/* Non-builtin types get wrapped in an ExtensionObject */
static status
encodeArrayJsonWrapExtensionObject(CtxJson *ctx, const void *data,
                                   size_t size, const UA_DataType *type) {
    if(size > UA_INT32_MAX)
        return UA_STATUSCODE_BADENCODINGERROR;

    status ret = writeJsonArrStart(ctx);

    u16 memSize = type->memSize;
    const UA_Boolean isBuiltin = (type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(isBuiltin) {
        uintptr_t ptr = (uintptr_t)data;
        for(size_t i = 0; i < size && ret == UA_STATUSCODE_GOOD; ++i) {
            ret |= writeJsonArrElm(ctx, (const void*)ptr, type);
            ptr += memSize;
        }
    } else {
        /* Set up a temporary ExtensionObject to wrap the data */
        UA_ExtensionObject eo;
        UA_ExtensionObject_init(&eo);
        eo.encoding = UA_EXTENSIONOBJECT_DECODED;
        eo.content.decoded.type = type;
        eo.content.decoded.data = (void*)(uintptr_t)data;
        for(size_t i = 0; i < size && ret == UA_STATUSCODE_GOOD; ++i) {
            ret |= writeJsonArrElm(ctx, &eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
            eo.content.decoded.data = (void*)
                ((uintptr_t)eo.content.decoded.data + memSize);
        }
    }

    return ret | writeJsonArrEnd(ctx, type);
}

static status
addMultiArrayContentJSON(CtxJson *ctx, void* array, const UA_DataType *type,
                         size_t *index, UA_UInt32 *arrayDimensions, size_t dimensionIndex,
                         size_t dimensionSize) {
    /* Stop recursion: The inner arrays are written */
    status ret;
    if(dimensionIndex == (dimensionSize - 1)) {
        u8 *ptr = ((u8 *)array) + (type->memSize * *index);
        u32 size = arrayDimensions[dimensionIndex];
        (*index) += arrayDimensions[dimensionIndex];
        return encodeArrayJsonWrapExtensionObject(ctx, ptr, size, type);
    }

    /* Recurse to the next dimension */
    ret = writeJsonArrStart(ctx);
    for(size_t i = 0; i < arrayDimensions[dimensionIndex]; i++) {
        ret |= writeJsonBeforeElement(ctx, true);
        ret |= addMultiArrayContentJSON(ctx, array, type, index, arrayDimensions,
                                        dimensionIndex + 1, dimensionSize);
        ctx->commaNeeded[ctx->depth] = true;
    }
    return ret | writeJsonArrEnd(ctx, type);
}

ENCODE_JSON(Variant) {
    /* If type is 0 (NULL) the Variant contains a NULL value and the containing
     * JSON object shall be omitted or replaced by the JSON literal ‘null’ (when
     * an element of a JSON array). */
    status ret = UA_STATUSCODE_GOOD;
    if(!src->type) {
        ret |= writeJsonObjStart(ctx);
        ret |= writeJsonObjEnd(ctx);
        return ret;
    }

    /* Set the content type in the encoding mask */
    const UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);

    /* Set the array type in the encoding mask */
    const bool isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL;
    const bool hasDimensions = isArray && src->arrayDimensionsSize > 0;

    /* We cannot directly encode a variant inside a variant (but arrays of
     * variant are possible) */
    UA_Boolean wrapEO = !isBuiltin;
    if(src->type == &UA_TYPES[UA_TYPES_VARIANT] && !isArray)
        wrapEO = true;
    if(ctx->prettyPrint)
        wrapEO = false; /* Don't wrap values in ExtensionObjects for pretty-printing */

    ret = writeJsonObjStart(ctx);

    /* Write the type NodeId */
    if(ctx->useReversible) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_TYPE);
        if(ctx->prettyPrint) {
            ret |= writeChars(ctx, src->type->typeName, strlen(src->type->typeName));
        } else {
            /* Write the NodeId for the reversible form */
            UA_UInt32 typeId = src->type->typeId.identifier.numeric;
            if(wrapEO)
                typeId = UA_TYPES[UA_TYPES_EXTENSIONOBJECT].typeId.identifier.numeric;
            ret |= ENCODE_DIRECT_JSON(&typeId, UInt32);
        }
    }

    /* Write the Variant body */
    ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);

    if(!isArray) {
        ret |= encodeScalarJsonWrapExtensionObject(ctx, src);
    } else {
        if(ctx->useReversible || !hasDimensions) {
            ret |= encodeArrayJsonWrapExtensionObject(ctx, src->data,
                                                      src->arrayLength, src->type);
            if(hasDimensions) {
                ret |= writeJsonKey(ctx, UA_JSONKEY_DIMENSION);
                ret |= encodeJsonArray(ctx, src->arrayDimensions, src->arrayDimensionsSize,
                                       &UA_TYPES[UA_TYPES_UINT32]);
            }
        } else {
            /* Special case of non-reversible array with dimensions */
            size_t index = 0;
            ret |= addMultiArrayContentJSON(ctx, src->data, src->type, &index,
                                            src->arrayDimensions, 0,
                                            src->arrayDimensionsSize);
        }
    }

    return ret | writeJsonObjEnd(ctx);
}

/* DataValue */
ENCODE_JSON(DataValue) {
    UA_Boolean hasValue = src->hasValue;
    UA_Boolean hasStatus = src->hasStatus;
    UA_Boolean hasSourceTimestamp = src->hasSourceTimestamp;
    UA_Boolean hasSourcePicoseconds = src->hasSourcePicoseconds;
    UA_Boolean hasServerTimestamp = src->hasServerTimestamp;
    UA_Boolean hasServerPicoseconds = src->hasServerPicoseconds;

    status ret = writeJsonObjStart(ctx);

    if(hasValue) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_VALUE);
        ret |= ENCODE_DIRECT_JSON(&src->value, Variant);
    }

    if(hasStatus) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_STATUS);
        ret |= ENCODE_DIRECT_JSON(&src->status, StatusCode);
    }

    if(hasSourceTimestamp) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SOURCETIMESTAMP);
        ret |= ENCODE_DIRECT_JSON(&src->sourceTimestamp, DateTime);
    }

    if(hasSourcePicoseconds) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SOURCEPICOSECONDS);
        ret |= ENCODE_DIRECT_JSON(&src->sourcePicoseconds, UInt16);
    }

    if(hasServerTimestamp) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERTIMESTAMP);
        ret |= ENCODE_DIRECT_JSON(&src->serverTimestamp, DateTime);
    }

    if(hasServerPicoseconds) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERPICOSECONDS);
        ret |= ENCODE_DIRECT_JSON(&src->serverPicoseconds, UInt16);
    }

    return ret | writeJsonObjEnd(ctx);
}

/* DiagnosticInfo */
ENCODE_JSON(DiagnosticInfo) {
    status ret = writeJsonObjStart(ctx);

    if(src->hasSymbolicId) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SYMBOLICID);
        ret |= ENCODE_DIRECT_JSON(&src->symbolicId, Int32);
    }

    if(src->hasNamespaceUri) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACEURI);
        ret |= ENCODE_DIRECT_JSON(&src->namespaceUri, Int32);
    }

    if(src->hasLocalizedText) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALIZEDTEXT);
        ret |= ENCODE_DIRECT_JSON(&src->localizedText, Int32);
    }

    if(src->hasLocale) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALE);
        ret |= ENCODE_DIRECT_JSON(&src->locale, Int32);
    }

    if(src->hasAdditionalInfo) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_ADDITIONALINFO);
        ret |= ENCODE_DIRECT_JSON(&src->additionalInfo, String);
    }

    if(src->hasInnerStatusCode) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_INNERSTATUSCODE);
        ret |= ENCODE_DIRECT_JSON(&src->innerStatusCode, StatusCode);
    }

    if(src->hasInnerDiagnosticInfo && src->innerDiagnosticInfo) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_INNERDIAGNOSTICINFO);
        ret |= encodeJsonJumpTable[UA_DATATYPEKIND_DIAGNOSTICINFO]
            (ctx, src->innerDiagnosticInfo, NULL);
    }

    return ret | writeJsonObjEnd(ctx);
}

static status
encodeJsonStructure(CtxJson *ctx, const void *src, const UA_DataType *type) {
    status ret = writeJsonObjStart(ctx);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    uintptr_t ptr = (uintptr_t) src;
    u8 membersSize = type->membersSize;
    for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;

        if(m->memberName != NULL && *m->memberName != 0)
            ret |= writeJsonKey(ctx, m->memberName);

        if(!m->isArray) {
            ptr += m->padding;
            size_t memSize = mt->memSize;
            ret |= encodeJsonJumpTable[mt->typeKind](ctx, (const void*) ptr, mt);
            ptr += memSize;
        } else {
            ptr += m->padding;
            const size_t length = *((const size_t*) ptr);
            ptr += sizeof (size_t);
            ret |= encodeJsonArray(ctx, *(void * const *)ptr, length, mt);
            ptr += sizeof (void*);
        }
    }

    return ret | writeJsonObjEnd(ctx);
}

static status
encodeJsonNotImplemented(const void *src, const UA_DataType *type, CtxJson *ctx) {
    (void) src, (void) type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const encodeJsonSignature encodeJsonJumpTable[UA_DATATYPEKINDS] = {
    (encodeJsonSignature)Boolean_encodeJson,
    (encodeJsonSignature)SByte_encodeJson, /* SByte */
    (encodeJsonSignature)Byte_encodeJson,
    (encodeJsonSignature)Int16_encodeJson, /* Int16 */
    (encodeJsonSignature)UInt16_encodeJson,
    (encodeJsonSignature)Int32_encodeJson, /* Int32 */
    (encodeJsonSignature)UInt32_encodeJson,
    (encodeJsonSignature)Int64_encodeJson, /* Int64 */
    (encodeJsonSignature)UInt64_encodeJson,
    (encodeJsonSignature)Float_encodeJson,
    (encodeJsonSignature)Double_encodeJson,
    (encodeJsonSignature)String_encodeJson,
    (encodeJsonSignature)DateTime_encodeJson, /* DateTime */
    (encodeJsonSignature)Guid_encodeJson,
    (encodeJsonSignature)ByteString_encodeJson, /* ByteString */
    (encodeJsonSignature)String_encodeJson, /* XmlElement */
    (encodeJsonSignature)NodeId_encodeJson,
    (encodeJsonSignature)ExpandedNodeId_encodeJson,
    (encodeJsonSignature)StatusCode_encodeJson, /* StatusCode */
    (encodeJsonSignature)QualifiedName_encodeJson, /* QualifiedName */
    (encodeJsonSignature)LocalizedText_encodeJson,
    (encodeJsonSignature)ExtensionObject_encodeJson,
    (encodeJsonSignature)DataValue_encodeJson,
    (encodeJsonSignature)Variant_encodeJson,
    (encodeJsonSignature)DiagnosticInfo_encodeJson,
    (encodeJsonSignature)encodeJsonNotImplemented, /* Decimal */
    (encodeJsonSignature)Int32_encodeJson, /* Enum */
    (encodeJsonSignature)encodeJsonStructure,
    (encodeJsonSignature)encodeJsonNotImplemented, /* Structure with optional fields */
    (encodeJsonSignature)encodeJsonNotImplemented, /* Union */
    (encodeJsonSignature)encodeJsonNotImplemented /* BitfieldCluster */
};

UA_StatusCode
UA_encodeJson(const void *src, const UA_DataType *type, UA_ByteString *outBuf,
              const UA_EncodeJsonOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate buffer */
    UA_Boolean allocated = false;
    status res = UA_STATUSCODE_GOOD;
    if(outBuf->length == 0) {
        size_t len = UA_calcSizeJson(src, type, options);
        res = UA_ByteString_allocBuffer(outBuf, len);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        allocated = true;
    }

    /* Set up the context */
    CtxJson ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = outBuf->data;
    ctx.end = &outBuf->data[outBuf->length];
    ctx.depth = 0;
    ctx.calcOnly = false;
    ctx.useReversible = true; /* default */
    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.useReversible = options->useReversible;
        ctx.prettyPrint = options->prettyPrint;
        ctx.unquotedKeys = options->unquotedKeys;
        ctx.stringNodeIds = options->stringNodeIds;
    }

    /* Encode */
    res = encodeJsonJumpTable[type->typeKind](&ctx, src, type);

    /* Clean up */
    if(res == UA_STATUSCODE_GOOD)
        outBuf->length = (size_t)((uintptr_t)ctx.pos - (uintptr_t)outBuf->data);
    else if(allocated)
        UA_ByteString_clear(outBuf);
    return res;
}

UA_StatusCode
UA_print(const void *p, const UA_DataType *type, UA_String *output) {
    if(!p || !type || !output)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_EncodeJsonOptions options;
    memset(&options, 0, sizeof(UA_EncodeJsonOptions));
    options.useReversible = true;
    options.prettyPrint = true;
    options.unquotedKeys = true;
    options.stringNodeIds = true;
    return UA_encodeJson(p, type, output, &options);
}

/************/
/* CalcSize */
/************/

size_t
UA_calcSizeJson(const void *src, const UA_DataType *type,
                const UA_EncodeJsonOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Set up the context */
    CtxJson ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = NULL;
    ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
    ctx.depth = 0;
    ctx.useReversible = true; /* default */
    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.useReversible = options->useReversible;
        ctx.prettyPrint = options->prettyPrint;
        ctx.unquotedKeys = options->unquotedKeys;
        ctx.stringNodeIds = options->stringNodeIds;
    }

    ctx.calcOnly = true;

    /* Encode */
    status ret = encodeJsonJumpTable[type->typeKind](&ctx, src, type);
    if(ret != UA_STATUSCODE_GOOD)
        return 0;
    return (size_t)ctx.pos;
}

/**********/
/* Decode */
/**********/

#define GET_TOKEN                                                       \
    size_t tokenSize = getTokenLength(&ctx->tokens[ctx->index]);        \
    const char* tokenData = &ctx->json5[ctx->tokens[ctx->index].start]; \
    do {} while(0)

#define CHECK_TOKEN_BOUNDS do {                   \
    if(ctx->index >= ctx->tokensSize)             \
        return UA_STATUSCODE_BADDECODINGERROR;    \
    } while(0)

#define CHECK_NUMBER do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_NUMBER) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_BOOL do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_BOOL) {      \
        return UA_STATUSCODE_BADDECODINGERROR;         \
    }} while(0)

#define CHECK_STRING do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_STRING) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_OBJECT do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_NULL_SKIP do {                         \
    if(currentTokenType(ctx) == CJ5_TOKEN_NULL) {    \
        ctx->index++;                                \
        return UA_STATUSCODE_GOOD;                   \
    }} while(0)

/* Forward declarations*/
#define DECODE_JSON(TYPE) static status                   \
    TYPE##_decodeJson(ParseCtx *ctx, UA_##TYPE *dst,      \
                      const UA_DataType *type)

/* If ctx->index points to the beginning of an object, move the index to the
 * next token after this object. Attention! The index can be moved after the
 * last parsed token. So the array length has to be checked afterwards. */
static void
skipObject(ParseCtx *ctx) {
    unsigned int end = ctx->tokens[ctx->index].end;
    do {
        ctx->index++;
    } while(ctx->index < ctx->tokensSize &&
            ctx->tokens[ctx->index].start < end);
}

static status
Array_decodeJson(ParseCtx *ctx, void **dst, const UA_DataType *type);

static status
Variant_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void *p, const UA_DataType *type);

static UA_SByte
jsoneq(const char *json, const cj5_token *tok, const char *searchKey) {
    /* TODO: necessary?
       if(json == NULL
            || tok == NULL
            || searchKey == NULL) {
        return -1;
    } */

    size_t len = getTokenLength(tok);
    if(tok->type == CJ5_TOKEN_STRING &&
       strlen(searchKey) ==  len &&
       strncmp(json + tok->start, (const char*)searchKey, len) == 0)
        return 0;

    return -1;
}

DECODE_JSON(Boolean) {
    CHECK_TOKEN_BOUNDS;
    CHECK_BOOL;
    GET_TOKEN;

    if(tokenSize == 4 &&
       (tokenData[0] | 32) == 't' && (tokenData[1] | 32) == 'r' &&
       (tokenData[2] | 32) == 'u' && (tokenData[3] | 32) == 'e') {
        *dst = true;
    } else if(tokenSize == 5 &&
              (tokenData[0] | 32) == 'f' && (tokenData[1] | 32) == 'a' &&
              (tokenData[2] | 32) == 'l' && (tokenData[3] | 32) == 's' &&
              (tokenData[4] | 32) == 'e') {
        *dst = false;
    } else {
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parseUnsignedInteger(const char *tokenData, size_t tokenSize, UA_UInt64 *dst) {
    size_t len = parseUInt64(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parseSignedInteger(const char *tokenData, size_t tokenSize, UA_Int64 *dst) {
    size_t len = parseInt64(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Byte) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_BYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Byte)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt16) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_UInt16)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt32) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_UInt32)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt64) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, dst);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(SByte) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_SBYTE_MIN || out > UA_SBYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_SByte)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int16) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT16_MIN || out > UA_INT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Int16)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int32) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT32_MIN || out > UA_INT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Int32)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int64) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, dst);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

/* Either a STRING or NUMBER token */
DECODE_JSON(Double) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    /* https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/
     * Maximum digit counts for select IEEE floating-point formats: 1074
     * Sanity check.
     */
    if(tokenSize > 2000)
        return UA_STATUSCODE_BADDECODINGERROR;

    cj5_token_type tokenType = currentTokenType(ctx);

    /* It could be a String with Nan, Infinity */
    if(tokenType == CJ5_TOKEN_STRING) {
        ctx->index++;

        if(tokenSize == 8 && memcmp(tokenData, "Infinity", 8) == 0) {
            *dst = INFINITY;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 9 && memcmp(tokenData, "-Infinity", 9) == 0) {
            /* workaround an MSVC 2013 issue */
            *dst = -INFINITY;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 3 && memcmp(tokenData, "NaN", 3) == 0) {
            *dst = NAN;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 4 && memcmp(tokenData, "-NaN", 4) == 0) {
            *dst = NAN;
            return UA_STATUSCODE_GOOD;
        }

        return UA_STATUSCODE_BADDECODINGERROR;
    }

    if(tokenType != CJ5_TOKEN_NUMBER)
        return UA_STATUSCODE_BADDECODINGERROR;

    size_t len = parseDouble(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Float) {
    UA_Double v = 0.0;
    UA_StatusCode res = Double_decodeJson(ctx, &v, NULL);
    *dst = (UA_Float)v;
    return res;
}

DECODE_JSON(Guid) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* Use the existing parsing routine if available */
    UA_String str = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
    ctx->index++;
    return UA_Guid_parse(dst, str);
}

DECODE_JSON(String) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;
    (void)tokenData;

    /* Empty string? */
    if(tokenSize == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
        ctx->index++;
        return UA_STATUSCODE_GOOD;
    }

    /* The decoded utf8 is at most of the same length as the source string */
    char *outBuf = (char*)UA_malloc(tokenSize+1);
    if(!outBuf)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode the string */
    cj5_result r;
    r.tokens = ctx->tokens;
    r.num_tokens = (unsigned int)ctx->tokensSize;
    r.json5 = ctx->json5;
    unsigned int len = 0;
    cj5_error_code err = cj5_get_str(&r, (unsigned int)ctx->index, outBuf, &len);
    if(err != CJ5_ERROR_NONE) {
        UA_free(outBuf);
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Set the output */
    dst->length = len;
    if(dst->length > 0) {
        dst->data = (UA_Byte*)outBuf;
    } else {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        UA_free(outBuf);
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(ByteString) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* Empty bytestring? */
    if(tokenSize == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
    } else {
        size_t flen = 0;
        unsigned char* unB64 =
            UA_unbase64((const unsigned char*)tokenData, tokenSize, &flen);
        if(unB64 == 0)
            return UA_STATUSCODE_BADDECODINGERROR;
        dst->data = (u8*)unB64;
        dst->length = flen;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(LocalizedText) {
    CHECK_OBJECT;

    DecodeEntry entries[2] = {
        {UA_JSONKEY_LOCALE, &dst->locale, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_TEXT, &dst->text, NULL, false, &UA_TYPES[UA_TYPES_STRING]}
    };

    return decodeFields(ctx, entries, 2);
}

DECODE_JSON(QualifiedName) {
    CHECK_OBJECT;

    DecodeEntry entries[2] = {
        {UA_JSONKEY_NAME, &dst->name, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_URI, &dst->namespaceIndex, NULL, false, &UA_TYPES[UA_TYPES_UINT16]}
    };

    return decodeFields(ctx, entries, 2);
}

UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT status
lookAheadForKey(ParseCtx *ctx, const char *key, size_t *resultIndex) {
    /* The current index must point to the beginning of an object.
     * This has to be ensured by the caller. */
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_OBJECT);

    status ret = UA_STATUSCODE_BADNOTFOUND;
    size_t oldIndex = ctx->index; /* Save index for later restore */
    unsigned int end = ctx->tokens[ctx->index].end;
    ctx->index++; /* Move to the first key */
    while(ctx->index < ctx->tokensSize &&
          ctx->tokens[ctx->index].start < end) {
        /* Key must be a string */
        UA_assert(currentTokenType(ctx) == CJ5_TOKEN_STRING);

        /* Move index to the value */
        ctx->index++;

        /* Value for the key must exist */
        UA_assert(ctx->index < ctx->tokensSize);

        /* Compare the key (previous index) */
        if(jsoneq(ctx->json5, &ctx->tokens[ctx->index-1], key) == 0) {
            *resultIndex = ctx->index; /* Point result to the current index */
            ret = UA_STATUSCODE_GOOD;
            break;
        }

        skipObject(ctx); /* Jump over the value (can also be an array or object) */
    }
    ctx->index = oldIndex; /* Restore the old index */
    return ret;
}

static status
prepareDecodeNodeIdJson(ParseCtx *ctx, UA_NodeId *dst,
                        u8 *fieldCount, DecodeEntry *entries) {
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_OBJECT);

    /* possible keys: Id, IdType, NamespaceIndex */
    /* Id must always be present */
    entries[*fieldCount].fieldName = UA_JSONKEY_ID;
    entries[*fieldCount].found = false;
    entries[*fieldCount].type = NULL;
    entries[*fieldCount].function = NULL;

    /* IdType */
    size_t idIndex = 0;
    status ret = lookAheadForKey(ctx, UA_JSONKEY_IDTYPE, &idIndex);
    if(ret == UA_STATUSCODE_GOOD) {
        size_t size = getTokenLength(&ctx->tokens[idIndex]);
        if(size < 1)
            return UA_STATUSCODE_BADDECODINGERROR;

        const char *idType = &ctx->json5[ctx->tokens[idIndex].start];

        if(idType[0] == '2') {
            dst->identifierType = UA_NODEIDTYPE_GUID;
            entries[*fieldCount].fieldPointer = &dst->identifier.guid;
            entries[*fieldCount].type = &UA_TYPES[UA_TYPES_GUID];
        } else if(idType[0] == '1') {
            dst->identifierType = UA_NODEIDTYPE_STRING;
            entries[*fieldCount].fieldPointer = &dst->identifier.string;
            entries[*fieldCount].type = &UA_TYPES[UA_TYPES_STRING];
        } else if(idType[0] == '3') {
            dst->identifierType = UA_NODEIDTYPE_BYTESTRING;
            entries[*fieldCount].fieldPointer = &dst->identifier.byteString;
            entries[*fieldCount].type = &UA_TYPES[UA_TYPES_BYTESTRING];
        } else {
            return UA_STATUSCODE_BADDECODINGERROR;
        }

        /* Id always present */
        (*fieldCount)++;

        entries[*fieldCount].fieldName = UA_JSONKEY_IDTYPE;
        entries[*fieldCount].fieldPointer = NULL;
        entries[*fieldCount].function = NULL;
        entries[*fieldCount].found = false;
        entries[*fieldCount].type = NULL;

        /* IdType */
        (*fieldCount)++;
    } else {
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        entries[*fieldCount].fieldPointer = &dst->identifier.numeric;
        entries[*fieldCount].function = NULL;
        entries[*fieldCount].found = false;
        entries[*fieldCount].type = &UA_TYPES[UA_TYPES_UINT32];
        (*fieldCount)++;
    }

    /* NodeId has a NamespaceIndex (the ExpandedNodeId specialization may
     * overwrite this) */
    entries[*fieldCount].fieldName = UA_JSONKEY_NAMESPACE;
    entries[*fieldCount].fieldPointer = &dst->namespaceIndex;
    entries[*fieldCount].function = NULL;
    entries[*fieldCount].found = false;
    entries[*fieldCount].type = &UA_TYPES[UA_TYPES_UINT16];
    (*fieldCount)++;

    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(NodeId) {
    /* Non-standard decoding of NodeIds from the string representation */
    if(currentTokenType(ctx) == CJ5_TOKEN_STRING) {
        GET_TOKEN;
        UA_String str = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
        ctx->index++;
        return UA_NodeId_parse(dst, str);
    }

    /* Object representation */
    CHECK_OBJECT;

    u8 fieldCount = 0;
    DecodeEntry entries[3];
    status ret = prepareDecodeNodeIdJson(ctx, dst, &fieldCount, entries);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    return decodeFields(ctx, entries, fieldCount);
}

static status
decodeExpandedNodeIdNamespace(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    UA_ExpandedNodeId *en = (UA_ExpandedNodeId*)dst;

    /* Parse as a number */
    size_t oldIndex = ctx->index;
    status ret = UInt16_decodeJson(ctx, &en->nodeId.namespaceIndex, NULL);
    if(ret == UA_STATUSCODE_GOOD)
        return ret;

    /* Parse as a string */
    ctx->index = oldIndex; /* Reset the index */
    ret = String_decodeJson(ctx, &en->namespaceUri, NULL);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Replace with the index if the URI is found. Otherwise keep the string. */
    if(ctx->namespaceMapping) {
        UA_StatusCode mapRes =
            UA_NamespaceMapping_uri2Index(ctx->namespaceMapping, en->namespaceUri,
                                          &en->nodeId.namespaceIndex);
        if(mapRes == UA_STATUSCODE_GOOD)
            UA_String_clear(&en->namespaceUri);
    }

    return UA_STATUSCODE_GOOD;
}

static status
decodeExpandedNodeIdServerUri(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    UA_ExpandedNodeId *en = (UA_ExpandedNodeId*)dst;

    /* Parse as a number */
    size_t oldIndex = ctx->index;
    status ret = UInt32_decodeJson(ctx, &en->serverIndex, NULL);
    if(ret == UA_STATUSCODE_GOOD)
        return ret;

    /* Parse as a string */
    UA_String uri = UA_STRING_NULL;
    ctx->index = oldIndex; /* Reset the index */
    ret = String_decodeJson(ctx, &uri, NULL);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Try to translate the URI into an index */
    ret = UA_STATUSCODE_BADDECODINGERROR;
    for(size_t i = 0; i < ctx->serverUrisSize; i++) {
        if(UA_String_equal(&uri, &ctx->serverUris[i])) {
            en->serverIndex = (UA_UInt32)i;
            ret = UA_STATUSCODE_GOOD;
            break;
        }
    }

    UA_String_clear(&uri);
    return ret;
}

DECODE_JSON(ExpandedNodeId) {
    /* Non-standard decoding of ExpandedNodeIds from the string representation */
    if(currentTokenType(ctx) == CJ5_TOKEN_STRING) {
        GET_TOKEN;
        UA_String str = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
        ctx->index++;
        return UA_ExpandedNodeId_parse(dst, str);
    }

    /* Object representation */
    CHECK_OBJECT;

    u8 fieldCount = 0;
    DecodeEntry entries[4];
    status ret = prepareDecodeNodeIdJson(ctx, &dst->nodeId, &fieldCount, entries);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Overwrite the namespace entry */
    fieldCount--;
    entries[fieldCount].fieldPointer = dst;
    entries[fieldCount].function = decodeExpandedNodeIdNamespace;
    entries[fieldCount].type = NULL;
    fieldCount++;

    entries[fieldCount].fieldName = UA_JSONKEY_SERVERURI;
    entries[fieldCount].fieldPointer = dst;
    entries[fieldCount].function = decodeExpandedNodeIdServerUri;
    entries[fieldCount].found = false;
    entries[fieldCount].type = NULL;
    fieldCount++;

    return decodeFields(ctx, entries, fieldCount);
}

DECODE_JSON(DateTime) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    UA_ByteString input = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
    UA_StatusCode res = UA_DateTime_parse(dst, input);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        ctx->index++;
    return res;
}

DECODE_JSON(StatusCode) {
    return UInt32_decodeJson(ctx, dst, NULL);
}

/* Get type type encoded by the ExtensionObject at ctx->index.
 * Returns NULL if that fails (type unknown or otherwise). */
static const UA_DataType *
getExtensionObjectType(ParseCtx *ctx) {
    if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT)
        return NULL;

    /* Get the type NodeId index */
    size_t typeIdIndex = 0;
    UA_StatusCode ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &typeIdIndex);
    if(ret != UA_STATUSCODE_GOOD)
        return NULL;

    size_t oldIndex = ctx->index;
    ctx->index = typeIdIndex;

    /* Decode the type NodeId */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    ret = NodeId_decodeJson(ctx, &typeId, &UA_TYPES[UA_TYPES_NODEID]);
    ctx->index = oldIndex;
    if(ret != UA_STATUSCODE_GOOD) {
        UA_NodeId_clear(&typeId); /* We don't have the global cleanup */
        return NULL;
    }

    /* Lookup an return */
    const UA_DataType *type = UA_findDataTypeWithCustom(&typeId, ctx->customTypes);
    UA_NodeId_clear(&typeId);
    return type;
}

/* Check if all array members are ExtensionObjects of the same type. Return this
 * type or NULL. */
static const UA_DataType *
getArrayUnwrapType(ParseCtx *ctx, size_t arrayIndex) {
    UA_assert(ctx->tokens[arrayIndex].type == CJ5_TOKEN_ARRAY);

    /* Save index to restore later */
    size_t oldIndex = ctx->index;
    ctx->index = arrayIndex;

    /* Return early for empty arrays */
    size_t length = (size_t)ctx->tokens[ctx->index].size;
    if(length == 0) {
        ctx->index = oldIndex; /* Restore the index */
        return NULL;
    }

    /* Go to first array member */
    ctx->index++;

    /* Lookup the type for the first array member */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    const UA_DataType *typeOfBody = getExtensionObjectType(ctx);
    if(!typeOfBody) {
        ctx->index = oldIndex; /* Restore the index */
        return NULL;
    }

    /* The content is a builtin type that could have been directly encoded in
     * the Variant, there was no need to wrap in an ExtensionObject. But this
     * means for us, that somebody made an extra effort to explicitly get an
     * ExtensionObject. So we keep it. As an added advantage we will generate
     * the same JSON again when encoding again. */
    UA_Boolean isBuiltin = (typeOfBody->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(isBuiltin) {
        ctx->index = oldIndex; /* Restore the index */
        return NULL;
    }

    /* Get the typeId index for faster comparison below.
     * Cannot fail as getExtensionObjectType already looked this up. */
    size_t typeIdIndex = 0;
    UA_StatusCode ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &typeIdIndex);
    (void)ret;
    UA_assert(ret == UA_STATUSCODE_GOOD);
    const char* typeIdData = &ctx->json5[ctx->tokens[typeIdIndex].start];
    size_t typeIdSize = getTokenLength(&ctx->tokens[typeIdIndex]);

    /* Loop over all members and check whether they can be unwrapped */
    for(size_t i = 0; i < length; i++) {
        /* Array element must be an object */
        if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Check for non-JSON encoding */
        size_t encIndex = 0;
        ret = lookAheadForKey(ctx, UA_JSONKEY_ENCODING, &encIndex);
        if(ret == UA_STATUSCODE_GOOD) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Get the type NodeId index */
        size_t memberTypeIdIndex = 0;
        ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &memberTypeIdIndex);
        if(ret != UA_STATUSCODE_GOOD) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Is it the same type? Compare raw NodeId string */
        const char* memberTypeIdData = &ctx->json5[ctx->tokens[memberTypeIdIndex].start];
        size_t memberTypeIdSize = getTokenLength(&ctx->tokens[memberTypeIdIndex]);
        if(typeIdSize != memberTypeIdSize ||
           memcmp(typeIdData, memberTypeIdData, typeIdSize) != 0) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Skip to the next array member */
        skipObject(ctx);
    }

    ctx->index = oldIndex; /* Restore the index */
    return typeOfBody;
}

static status
Array_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void **dst, const UA_DataType *type) {
    size_t *size_ptr = (size_t*) dst - 1; /* Save the length pointer of the array */
    size_t length = (size_t)ctx->tokens[ctx->index].size;

    /* Known from the previous unwrapping-check */
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_ARRAY);
    UA_assert(length > 0);

    ctx->index++; /* Go to first array member */

    /* Allocate memory */
    *dst = UA_calloc(length, type->memSize);
    if(*dst == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode array members */
    uintptr_t ptr = (uintptr_t)*dst;
    for(size_t i = 0; i < length; i++) {
        UA_assert(ctx->tokens[ctx->index].type == CJ5_TOKEN_OBJECT);

        /* Get the body field and decode it */
        DecodeEntry entries[3] = {
            {UA_JSONKEY_TYPEID, NULL, NULL, false, NULL},
            {UA_JSONKEY_BODY, (void*)ptr, NULL, false, type},
            {UA_JSONKEY_ENCODING, NULL, NULL, false, NULL}
        };
        status ret = decodeFields(ctx, entries, 3); /* Also skips to the next object */
        if(ret != UA_STATUSCODE_GOOD) {
            UA_Array_delete(*dst, i+1, type);
            *dst = NULL;
            return ret;
        }
        ptr += type->memSize;
    }

    *size_ptr = length; /* All good, set the size */
    return UA_STATUSCODE_GOOD;
}

static status
decodeVariantBodyWithType(ParseCtx *ctx, UA_Variant *dst, size_t bodyIndex,
                          size_t *dimIndex, const UA_DataType *type) {
    /* Value is an array? */
    UA_Boolean isArray = (ctx->tokens[bodyIndex].type == CJ5_TOKEN_ARRAY);

    /* TODO: Handling of null-arrays (length -1) needs to be clarified
     *
     * if(tokenIsNull(ctx, bodyIndex)) {
     *     isArray = true;
     *     dst->arrayLength = 0;
     * } */

    /* No array but has dimension -> error */
    if(!isArray && dimIndex)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Get the datatype of the content. The type must be a builtin data type.
     * All not-builtin types are wrapped in an ExtensionObject. */
    if(type->typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* A variant cannot contain a variant. But it can contain an array of
     * variants */
    if(type->typeKind == UA_DATATYPEKIND_VARIANT && !isArray)
        return UA_STATUSCODE_BADDECODINGERROR;

    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADDECODINGERROR;
    ctx->depth++;
    ctx->index = bodyIndex;

    /* Decode an array */
    status res = UA_STATUSCODE_GOOD;
    if(isArray) {
        /* Try to unwrap ExtensionObjects in the array.
         * The members must all have the same type. */
        const UA_DataType *unwrapType = NULL;
        if(type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT] &&
           (unwrapType = getArrayUnwrapType(ctx, bodyIndex))) {
            dst->type = unwrapType;
            res = Array_decodeJsonUnwrapExtensionObject(ctx, &dst->data, unwrapType);
        } else {
            dst->type = type;
            res = Array_decodeJson(ctx, &dst->data, type);
        }

        /* Decode array dimensions */
        if(dimIndex) {
            ctx->index = *dimIndex;
            res |= Array_decodeJson(ctx, (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
        }
        ctx->depth--;
        return res;
    }

    /* Decode a value wrapped in an ExtensionObject */
    if(type->typeKind == UA_DATATYPEKIND_EXTENSIONOBJECT) {
        res = Variant_decodeJsonUnwrapExtensionObject(ctx, dst, NULL);
        goto out;
    }

    /* Allocate Memory for Body */
    dst->data = UA_new(type);
    if(!dst->data) {
        res = UA_STATUSCODE_BADOUTOFMEMORY;
        goto out;
    }

    /* Decode the body */
    dst->type = type;
    if(ctx->tokens[ctx->index].type != CJ5_TOKEN_NULL)
        res = decodeJsonJumpTable[type->typeKind](ctx, dst->data, type);

 out:
    ctx->depth--;
    return res;
}

DECODE_JSON(Variant) {
    CHECK_NULL_SKIP; /* Treat null as an empty variant */
    CHECK_OBJECT;

    /* First search for the variant type in the json object. */
    size_t typeIndex = 0;
    status ret = lookAheadForKey(ctx, UA_JSONKEY_TYPE, &typeIndex);
    if(ret != UA_STATUSCODE_GOOD) {
        skipObject(ctx);
        return UA_STATUSCODE_GOOD;
    }

    /* Parse the type */
    if(ctx->tokens[typeIndex].type != CJ5_TOKEN_NUMBER)
        return UA_STATUSCODE_BADDECODINGERROR;
    UA_UInt64 idType = 0;
    size_t len = parseUInt64(&ctx->json5[ctx->tokens[typeIndex].start],
                             getTokenLength(&ctx->tokens[typeIndex]), &idType);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* A NULL Variant */
    if(idType == 0) {
        skipObject(ctx);
        return UA_STATUSCODE_GOOD;
    }

    /* Set the type */
    UA_NodeId typeNodeId = UA_NODEID_NUMERIC(0, (UA_UInt32)idType);
    type = UA_findDataTypeWithCustom(&typeNodeId, ctx->customTypes);
    if(!type)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Search for body */
    size_t bodyIndex = 0;
    ret = lookAheadForKey(ctx, UA_JSONKEY_BODY, &bodyIndex);
    if(ret != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Search for the dimensions */
    size_t *dimPtr = NULL;
    size_t dimIndex = 0;
    ret = lookAheadForKey(ctx, UA_JSONKEY_DIMENSION, &dimIndex);
    if(ret == UA_STATUSCODE_GOOD && ctx->tokens[dimIndex].size > 0)
        dimPtr = &dimIndex;

    /* Decode the body */
    return decodeVariantBodyWithType(ctx, dst, bodyIndex, dimPtr, type);
}

DECODE_JSON(DataValue) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DataValue */
    CHECK_OBJECT;

    DecodeEntry entries[6] = {
        {UA_JSONKEY_VALUE, &dst->value, NULL, false, &UA_TYPES[UA_TYPES_VARIANT]},
        {UA_JSONKEY_STATUS, &dst->status, NULL, false, &UA_TYPES[UA_TYPES_STATUSCODE]},
        {UA_JSONKEY_SOURCETIMESTAMP, &dst->sourceTimestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
        {UA_JSONKEY_SOURCEPICOSECONDS, &dst->sourcePicoseconds, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
        {UA_JSONKEY_SERVERTIMESTAMP, &dst->serverTimestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
        {UA_JSONKEY_SERVERPICOSECONDS, &dst->serverPicoseconds, NULL, false, &UA_TYPES[UA_TYPES_UINT16]}
    };

    status ret = decodeFields(ctx, entries, 6);
    dst->hasValue = entries[0].found;
    dst->hasStatus = entries[1].found;
    dst->hasSourceTimestamp = entries[2].found;
    dst->hasSourcePicoseconds = entries[3].found;
    dst->hasServerTimestamp = entries[4].found;
    dst->hasServerPicoseconds = entries[5].found;
    return ret;
}

/* Move the entire current token into the target bytestring */
static UA_StatusCode
tokenToByteString(ParseCtx *ctx, UA_ByteString *p, const UA_DataType *type) {
    GET_TOKEN;
    UA_StatusCode res = UA_ByteString_allocBuffer(p, tokenSize);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    memcpy(p->data, tokenData, tokenSize);
    skipObject(ctx);
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(ExtensionObject) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DataValue */
    CHECK_OBJECT;

    /* Empty object -> Null ExtensionObject */
    if(ctx->tokens[ctx->index].size == 0) {
        ctx->index++; /* Skip the empty ExtensionObject */
        return UA_STATUSCODE_GOOD;
    }

    /* Search for non-JSON encoding */
    UA_UInt64 encoding = 0;
    size_t encIndex = 0;
    status ret = lookAheadForKey(ctx, UA_JSONKEY_ENCODING, &encIndex);
    if(ret == UA_STATUSCODE_GOOD) {
        const char *extObjEncoding = &ctx->json5[ctx->tokens[encIndex].start];
        size_t len = parseUInt64(extObjEncoding, getTokenLength(&ctx->tokens[encIndex]),
                                 &encoding);
        if(len == 0)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Lookup the DataType for the ExtensionObject if the body can be decoded */
    const UA_DataType *typeOfBody = (encoding == 0) ? getExtensionObjectType(ctx) : NULL;

    /* Keep the encoded body */
    if(!typeOfBody) {
        DecodeEntry entries[3] = {
            {UA_JSONKEY_ENCODING, NULL, NULL, false, NULL},
            {UA_JSONKEY_TYPEID, &dst->content.encoded.typeId, NULL, false, &UA_TYPES[UA_TYPES_NODEID]},
            {UA_JSONKEY_BODY, &dst->content.encoded.body, NULL, false, &UA_TYPES[UA_TYPES_STRING]}
        };

        if(encoding == 0) {
            entries[2].function = (decodeJsonSignature)tokenToByteString;
            dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; /* ByteString in Json Body */
        } else if(encoding == 1) {
            dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; /* ByteString in Json Body */
        } else if(encoding == 2) {
            dst->encoding = UA_EXTENSIONOBJECT_ENCODED_XML; /* XmlElement in Json Body */
        } else {
            return UA_STATUSCODE_BADDECODINGERROR;
        }
        return decodeFields(ctx, entries, 3);
    }

    /* Allocate memory for the decoded data */
    dst->content.decoded.data = UA_new(typeOfBody);
    if(!dst->content.decoded.data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set type */
    dst->content.decoded.type = typeOfBody;
    dst->encoding = UA_EXTENSIONOBJECT_DECODED;

    /* Decode body */
    DecodeEntry entries[3] = {
        {UA_JSONKEY_ENCODING, NULL, NULL, false, NULL},
        {UA_JSONKEY_TYPEID, NULL, NULL, false, NULL},
        {UA_JSONKEY_BODY, dst->content.decoded.data, NULL, false, typeOfBody}
    };
    return decodeFields(ctx, entries, 3);
}

static status
Variant_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void *p, const UA_DataType *type) {
    (void) type;
    UA_Variant *dst = (UA_Variant*)p;

    /* ExtensionObject with null body */
    if(currentTokenType(ctx) == CJ5_TOKEN_NULL) {
        dst->data = UA_ExtensionObject_new();
        dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
        ctx->index++;
        return UA_STATUSCODE_GOOD;
    }

    /* Decode the ExtensionObject */
    UA_ExtensionObject eo;
    UA_ExtensionObject_init(&eo);
    UA_StatusCode ret = ExtensionObject_decodeJson(ctx, &eo, NULL);
    if(ret != UA_STATUSCODE_GOOD) {
        UA_ExtensionObject_clear(&eo); /* We don't have the global cleanup */
        return ret;
    }

    /* The content is still encoded, cannot unwrap */
    if(eo.encoding != UA_EXTENSIONOBJECT_DECODED)
        goto use_eo;

    /* The content is a builtin type that could have been directly encoded in
     * the Variant, there was no need to wrap in an ExtensionObject. But this
     * means for us, that somebody made an extra effort to explicitly get an
     * ExtensionObject. So we keep it. As an added advantage we will generate
     * the same JSON again when encoding again. */
    UA_Boolean isBuiltin =
        (eo.content.decoded.type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(isBuiltin)
        goto use_eo;

    /* Unwrap the ExtensionObject */
    dst->data = eo.content.decoded.data;
    dst->type = eo.content.decoded.type;
    return UA_STATUSCODE_GOOD;

 use_eo:
    /* Don't unwrap */
    dst->data = UA_new(&UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
    if(!dst->data) {
        UA_ExtensionObject_clear(&eo);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
    *(UA_ExtensionObject*)dst->data = eo;
    return UA_STATUSCODE_GOOD;
}

status
DiagnosticInfoInner_decodeJson(ParseCtx* ctx, void* dst, const UA_DataType* type);

DECODE_JSON(DiagnosticInfo) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DiagnosticInfo */
    CHECK_OBJECT;

    DecodeEntry entries[7] = {
        {UA_JSONKEY_SYMBOLICID, &dst->symbolicId, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_NAMESPACEURI, &dst->namespaceUri, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_LOCALIZEDTEXT, &dst->localizedText, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_LOCALE, &dst->locale, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_ADDITIONALINFO, &dst->additionalInfo, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_INNERSTATUSCODE, &dst->innerStatusCode, NULL, false, &UA_TYPES[UA_TYPES_STATUSCODE]},
        {UA_JSONKEY_INNERDIAGNOSTICINFO, &dst->innerDiagnosticInfo, DiagnosticInfoInner_decodeJson, false, NULL}
    };
    status ret = decodeFields(ctx, entries, 7);

    dst->hasSymbolicId = entries[0].found;
    dst->hasNamespaceUri = entries[1].found;
    dst->hasLocalizedText = entries[2].found;
    dst->hasLocale = entries[3].found;
    dst->hasAdditionalInfo = entries[4].found;
    dst->hasInnerStatusCode = entries[5].found;
    dst->hasInnerDiagnosticInfo = entries[6].found;
    return ret;
}

status
DiagnosticInfoInner_decodeJson(ParseCtx* ctx, void* dst, const UA_DataType* type) {
    UA_DiagnosticInfo *inner = (UA_DiagnosticInfo*)
        UA_calloc(1, sizeof(UA_DiagnosticInfo));
    if(!inner)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_DiagnosticInfo **dst2 = (UA_DiagnosticInfo**)dst;
    *dst2 = inner;  /* Copy new Pointer do dest */
    return DiagnosticInfo_decodeJson(ctx, inner, type);
}

status
decodeFields(ParseCtx *ctx, DecodeEntry *entries, size_t entryCount) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NULL_SKIP; /* null is treated like an empty object */

    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Keys and values are counted separately */
    CHECK_OBJECT;
    UA_assert(ctx->tokens[ctx->index].size % 2 == 0);
    size_t keyCount = (size_t)(ctx->tokens[ctx->index].size) / 2;

    ctx->index++; /* Go to first key - or jump after the empty object */
    ctx->depth++;

    status ret = UA_STATUSCODE_GOOD;
    for(size_t key = 0; key < keyCount; key++) {
        /* Key must be a string */
        UA_assert(ctx->index < ctx->tokensSize);
        UA_assert(currentTokenType(ctx) == CJ5_TOKEN_STRING);

        /* Search for the decoding entry matching the key. Start at the key
         * index to speed-up the case where they key-order is the same as the
         * entry-order. */
        DecodeEntry *entry = NULL;
        for(size_t i = key; i < key + entryCount; i++) {
            size_t ii = i;
            while(ii >= entryCount)
                ii -= entryCount;

            /* Compare the key */
            if(jsoneq(ctx->json5, &ctx->tokens[ctx->index],
                      entries[ii].fieldName) != 0)
                continue;

            /* Key was already used -> duplicate, abort */
            if(entries[ii].found) {
                ctx->depth--;
                return UA_STATUSCODE_BADDECODINGERROR;
            }

            /* Found the key */
            entries[ii].found = true;
            entry = &entries[ii];
            break;
        }

        /* The key is unknown */
        if(!entry) {
            ret = UA_STATUSCODE_BADDECODINGERROR;
            break;
        }

        /* Go from key to value */
        ctx->index++;
        UA_assert(ctx->index < ctx->tokensSize);

        /* An entry that was expected but shall not be decoded.
         * Jump over the value. */
        if(!entry->function && !entry->type) {
            skipObject(ctx);
            continue;
        }

        /* A null-value, skip the decoding (the value is already initialized) */
        if(currentTokenType(ctx) == CJ5_TOKEN_NULL && !entry->function) {
            ctx->index++; /* skip null value */
            continue;
        }

        /* Decode. This also moves to the next key or right after the object for
         * the last value. */
        decodeJsonSignature decodeFunc = (entry->function) ?
            entry->function : decodeJsonJumpTable[entry->type->typeKind];
        ret = decodeFunc(ctx, entry->fieldPointer, entry->type);
        if(ret != UA_STATUSCODE_GOOD)
            break;
    }

    ctx->depth--;
    return ret;
}

static status
Array_decodeJson(ParseCtx *ctx, void **dst, const UA_DataType *type) {
    /* Save the length of the array */
    size_t *size_ptr = (size_t*) dst - 1;

    if(currentTokenType(ctx) != CJ5_TOKEN_ARRAY)
        return UA_STATUSCODE_BADDECODINGERROR;

    size_t length = (size_t)ctx->tokens[ctx->index].size;

    ctx->index++; /* Go to first array member or to the first element after
                   * the array (if empty) */

    /* Return early for empty arrays */
    if(length == 0) {
        *size_ptr = length;
        *dst = UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }

    /* Allocate memory */
    *dst = UA_calloc(length, type->memSize);
    if(*dst == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode array members */
    uintptr_t ptr = (uintptr_t)*dst;
    for(size_t i = 0; i < length; ++i) {
        if(ctx->tokens[ctx->index].type != CJ5_TOKEN_NULL) {
            status ret = decodeJsonJumpTable[type->typeKind](ctx, (void*)ptr, type);
            if(ret != UA_STATUSCODE_GOOD) {
                UA_Array_delete(*dst, i+1, type);
                *dst = NULL;
                return ret;
            }
        } else {
            ctx->index++;
        }
        ptr += type->memSize;
    }

    *size_ptr = length; /* All good, set the size */
    return UA_STATUSCODE_GOOD;
}

static status
decodeJsonStructure(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    /* Check the recursion limit */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    status ret = UA_STATUSCODE_GOOD;
    u8 membersSize = type->membersSize;
    UA_STACKARRAY(DecodeEntry, entries, membersSize);
    for(size_t i = 0; i < membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        entries[i].type = mt;
        entries[i].fieldName = m->memberName;
        entries[i].found = false;
        if(!m->isArray) {
            ptr += m->padding;
            entries[i].fieldPointer = (void*)ptr;
            entries[i].function = NULL;
            ptr += mt->memSize;
        } else {
            ptr += m->padding;
            ptr += sizeof(size_t);
            entries[i].fieldPointer = (void*)ptr;
            entries[i].function = (decodeJsonSignature)Array_decodeJson;
            ptr += sizeof(void*);
        }
    }

    ret = decodeFields(ctx, entries, membersSize);

    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth--;
    return ret;
}

static status
decodeJsonNotImplemented(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    (void)dst, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const decodeJsonSignature decodeJsonJumpTable[UA_DATATYPEKINDS] = {
    (decodeJsonSignature)Boolean_decodeJson,
    (decodeJsonSignature)SByte_decodeJson, /* SByte */
    (decodeJsonSignature)Byte_decodeJson,
    (decodeJsonSignature)Int16_decodeJson, /* Int16 */
    (decodeJsonSignature)UInt16_decodeJson,
    (decodeJsonSignature)Int32_decodeJson, /* Int32 */
    (decodeJsonSignature)UInt32_decodeJson,
    (decodeJsonSignature)Int64_decodeJson, /* Int64 */
    (decodeJsonSignature)UInt64_decodeJson,
    (decodeJsonSignature)Float_decodeJson,
    (decodeJsonSignature)Double_decodeJson,
    (decodeJsonSignature)String_decodeJson,
    (decodeJsonSignature)DateTime_decodeJson, /* DateTime */
    (decodeJsonSignature)Guid_decodeJson,
    (decodeJsonSignature)ByteString_decodeJson, /* ByteString */
    (decodeJsonSignature)String_decodeJson, /* XmlElement */
    (decodeJsonSignature)NodeId_decodeJson,
    (decodeJsonSignature)ExpandedNodeId_decodeJson,
    (decodeJsonSignature)StatusCode_decodeJson, /* StatusCode */
    (decodeJsonSignature)QualifiedName_decodeJson, /* QualifiedName */
    (decodeJsonSignature)LocalizedText_decodeJson,
    (decodeJsonSignature)ExtensionObject_decodeJson,
    (decodeJsonSignature)DataValue_decodeJson,
    (decodeJsonSignature)Variant_decodeJson,
    (decodeJsonSignature)DiagnosticInfo_decodeJson,
    (decodeJsonSignature)decodeJsonNotImplemented, /* Decimal */
    (decodeJsonSignature)Int32_decodeJson, /* Enum */
    (decodeJsonSignature)decodeJsonStructure,
    (decodeJsonSignature)decodeJsonNotImplemented, /* Structure with optional fields */
    (decodeJsonSignature)decodeJsonNotImplemented, /* Union */
    (decodeJsonSignature)decodeJsonNotImplemented /* BitfieldCluster */
};

status
tokenize(ParseCtx *ctx, const UA_ByteString *src, size_t tokensSize,
         size_t *decodedLength) {
    /* Tokenize */
    cj5_options options;
    options.stop_early = (decodedLength != NULL);
    cj5_result r = cj5_parse((char*)src->data, (unsigned int)src->length,
                             ctx->tokens, (unsigned int)tokensSize, &options);

    /* Handle overflow error by allocating the number of tokens the parser would
     * have needed */
    if(r.error == CJ5_ERROR_OVERFLOW &&
       tokensSize != r.num_tokens) {
        ctx->tokens = (cj5_token*)
            UA_malloc(sizeof(cj5_token) * r.num_tokens);
        if(!ctx->tokens)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        return tokenize(ctx, src, r.num_tokens, decodedLength);
    }

    /* Cannot recover from other errors */
    if(r.error != CJ5_ERROR_NONE)
        return UA_STATUSCODE_BADDECODINGERROR;

    if(decodedLength)
        *decodedLength = ctx->tokens[0].end + 1;

    /* Set up the context */
    ctx->json5 = (char*)src->data;
    ctx->depth = 0;
    ctx->tokensSize = r.num_tokens;
    ctx->index = 0;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type,
              const UA_DecodeJsonOptions *options) {
    if(!dst || !src || !type)
        return UA_STATUSCODE_BADARGUMENTSMISSING;

    /* Set up the context */
    cj5_token tokens[UA_JSON_MAXTOKENCOUNT];
    ParseCtx ctx;
    memset(&ctx, 0, sizeof(ParseCtx));
    ctx.tokens = tokens;

    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.customTypes = options->customTypes;
    }

    /* Decode */
    status ret = tokenize(&ctx, src, UA_JSON_MAXTOKENCOUNT,
                          options ? options->decodedLength : NULL);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;

    memset(dst, 0, type->memSize); /* Initialize the value */
    ret = decodeJsonJumpTable[type->typeKind](&ctx, dst, type);

    /* Sanity check if all tokens were processed */
    if(ctx.index != ctx.tokensSize &&
       ctx.index != ctx.tokensSize - 1)
        ret = UA_STATUSCODE_BADDECODINGERROR;

 cleanup:

    /* Free token array on the heap */
    if(ctx.tokens != tokens)
        UA_free((void*)(uintptr_t)ctx.tokens);

    if(ret != UA_STATUSCODE_GOOD)
        UA_clear(dst, type);
    return ret;
}

#endif /* UA_ENABLE_JSON_ENCODING_LEGACY */

/**** amalgamated original file "/src/ua_types_encoding_json_105.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018, 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Lukas Meling)
 */

/**
 * This file contains the JSON encoding/decoding following the v1.05 OPC UA
 * specification. The changes in the v1.05 specification are breaking. The
 * encoding is not compatible with previous versions. Enable
 * UA_ENABLE_JSON_ENCODING_LEGACY to use the old JSON encoding instead.
 */


#if defined(UA_ENABLE_JSON_ENCODING) && !defined(UA_ENABLE_JSON_ENCODING_LEGACY)


#include <float.h>
#include <math.h>


#if defined(_MSC_VER)
# pragma warning(disable: 4756)
# pragma warning(disable: 4056)
#endif

/************/
/* Encoding */
/************/

static status
encodeJsonStructureContent(CtxJson *ctx, const void *src, const UA_DataType *type);

static status
decodeJsonStructure(ParseCtx *ctx, void *dst, const UA_DataType *type);

#define ENCODE_JSON(TYPE) static status \
    TYPE##_encodeJson(CtxJson *ctx, const UA_##TYPE *src, const UA_DataType *type)

#define ENCODE_DIRECT_JSON(SRC, TYPE) \
    TYPE##_encodeJson(ctx, (const UA_##TYPE*)SRC, NULL)

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeChar(CtxJson *ctx, char c) {
    if(ctx->pos >= ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        *ctx->pos = (UA_Byte)c;
    ctx->pos++;
    return UA_STATUSCODE_GOOD;
}

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeChars(CtxJson *ctx, const char *c, size_t len) {
    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        memcpy(ctx->pos, c, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

#define WRITE_JSON_ELEMENT(ELEM)                            \
    UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT status                  \
    writeJson##ELEM(CtxJson *ctx)

static WRITE_JSON_ELEMENT(Quote) {
    return writeChar(ctx, '\"');
}

UA_StatusCode
writeJsonBeforeElement(CtxJson *ctx, UA_Boolean distinct) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    /* Comma if needed */
    if(ctx->commaNeeded[ctx->depth])
        res |= writeChar(ctx, ',');
    if(ctx->prettyPrint) {
        if(distinct) {
            /* Newline and indent if needed */
            res |= writeChar(ctx, '\n');
            for(size_t i = 0; i < ctx->depth; i++)
                res |= writeChar(ctx, '\t');
        } else if(ctx->commaNeeded[ctx->depth]) {
            /* Space after the comma if no newline */
            res |= writeChar(ctx, ' ');
        }
    }
    return res;
}

WRITE_JSON_ELEMENT(ObjStart) {
    /* increase depth, save: before first key-value no comma needed. */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;
    ctx->commaNeeded[ctx->depth] = false;
    return writeChar(ctx, '{');
}

WRITE_JSON_ELEMENT(ObjEnd) {
    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;

    UA_Boolean have_elem = ctx->commaNeeded[ctx->depth];
    ctx->depth--;
    ctx->commaNeeded[ctx->depth] = true;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ctx->prettyPrint && have_elem) {
        res |= writeChar(ctx, '\n');
        for(size_t i = 0; i < ctx->depth; i++)
            res |= writeChar(ctx, '\t');
    }
    return res | writeChar(ctx, '}');
}

WRITE_JSON_ELEMENT(ArrStart) {
    /* increase depth, save: before first array entry no comma needed. */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;
    ctx->commaNeeded[ctx->depth] = false;
    return writeChar(ctx, '[');
}

status
writeJsonArrEnd(CtxJson *ctx, const UA_DataType *type) {
    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    UA_Boolean have_elem = ctx->commaNeeded[ctx->depth];
    ctx->depth--;
    ctx->commaNeeded[ctx->depth] = true;

    /* If the array does not contain JSON objects (with a newline after), then
     * add the closing ] on the same line */
    UA_Boolean distinct = (!type || type->typeKind > UA_DATATYPEKIND_DOUBLE);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ctx->prettyPrint && have_elem && distinct) {
        res |= writeChar(ctx, '\n');
        for(size_t i = 0; i < ctx->depth; i++)
            res |= writeChar(ctx, '\t');
    }
    return res | writeChar(ctx, ']');
}

status
writeJsonArrElm(CtxJson *ctx, const void *value,
                const UA_DataType *type) {
    UA_Boolean distinct = (type->typeKind > UA_DATATYPEKIND_DOUBLE);
    status ret = writeJsonBeforeElement(ctx, distinct);
    ctx->commaNeeded[ctx->depth] = true;
    return ret | encodeJsonJumpTable[type->typeKind](ctx, value, type);
}

status
writeJsonObjElm(CtxJson *ctx, const char *key,
                const void *value, const UA_DataType *type) {
    status ret = writeJsonKey(ctx, key);
    return ret | encodeJsonJumpTable[type->typeKind](ctx, value, type);
}

/* Keys for JSON */

/* LocalizedText */
static const char* UA_JSONKEY_LOCALE = "Locale";
static const char* UA_JSONKEY_TEXT = "Text";

/* Variant */
static const char* UA_JSONKEY_TYPE = "UaType";
static const char* UA_JSONKEY_VALUE = "Value";
static const char* UA_JSONKEY_DIMENSIONS = "Dimensions";

/* DataValue */
static const char* UA_JSONKEY_STATUS = "Status";
static const char* UA_JSONKEY_SOURCETIMESTAMP = "SourceTimestamp";
static const char* UA_JSONKEY_SOURCEPICOSECONDS = "SourcePicoseconds";
static const char* UA_JSONKEY_SERVERTIMESTAMP = "ServerTimestamp";
static const char* UA_JSONKEY_SERVERPICOSECONDS = "ServerPicoseconds";

/* ExtensionObject */
static const char* UA_JSONKEY_ENCODING = "UaEncoding";
static const char* UA_JSONKEY_TYPEID = "UaTypeId";
static const char* UA_JSONKEY_BODY = "UaBody";

/* StatusCode */
static const char* UA_JSONKEY_CODE = "Code";
static const char* UA_JSONKEY_SYMBOL = "Symbol";

/* DiagnosticInfo */
static const char* UA_JSONKEY_SYMBOLICID = "SymbolicId";
static const char* UA_JSONKEY_NAMESPACEURI = "NamespaceUri";
static const char* UA_JSONKEY_LOCALIZEDTEXT = "LocalizedText";
static const char* UA_JSONKEY_ADDITIONALINFO = "AdditionalInfo";
static const char* UA_JSONKEY_INNERSTATUSCODE = "InnerStatusCode";
static const char* UA_JSONKEY_INNERDIAGNOSTICINFO = "InnerDiagnosticInfo";

/* Writes null terminated string to output buffer (current ctx->pos). Writes
 * comma in front of key if needed. Encapsulates key in quotes. */
status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeJsonKey(CtxJson *ctx, const char* key) {
    status ret = writeJsonBeforeElement(ctx, true);
    ctx->commaNeeded[ctx->depth] = true;
    if(!ctx->unquotedKeys)
        ret |= writeChar(ctx, '\"');
    ret |= writeChars(ctx, key, strlen(key));
    if(!ctx->unquotedKeys)
        ret |= writeChar(ctx, '\"');
    ret |= writeChar(ctx, ':');
    if(ctx->prettyPrint)
        ret |= writeChar(ctx, ' ');
    return ret;
}

static bool
isNull(const void *p, const UA_DataType *type) {
    if(UA_DataType_isNumeric(type) || type->typeKind == UA_DATATYPEKIND_BOOLEAN)
        return false;
    UA_STACKARRAY(char, buf, type->memSize);
    memset(buf, 0, type->memSize);
    return UA_equal(buf, p, type);
}

/* Boolean */
ENCODE_JSON(Boolean) {
    if(*src == true)
        return writeChars(ctx, "true", 4);
    return writeChars(ctx, "false", 5);
}

/* Byte */
ENCODE_JSON(Byte) {
    char buf[4];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    /* Ensure destination can hold the data- */
    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    /* Copy digits to the output string/buffer. */
    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* signed Byte */
ENCODE_JSON(SByte) {
    char buf[5];
    UA_UInt16 digits = itoaSigned(*src, buf);
    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt16 */
ENCODE_JSON(UInt16) {
    char buf[6];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* Int16 */
ENCODE_JSON(Int16) {
    char buf[7];
    UA_UInt16 digits = itoaSigned(*src, buf);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt32 */
ENCODE_JSON(UInt32) {
    char buf[11];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* Int32 */
ENCODE_JSON(Int32) {
    char buf[12];
    UA_UInt16 digits = itoaSigned(*src, buf);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt64 */
ENCODE_JSON(UInt64) {
    char buf[23];
    buf[0] = '\"';
    UA_UInt16 digits = itoaUnsigned(*src, buf + 1, 10);
    buf[digits + 1] = '\"';
    UA_UInt16 length = (UA_UInt16)(digits + 2);

    if(ctx->pos + length > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, length);
    ctx->pos += length;
    return UA_STATUSCODE_GOOD;
}

/* Int64 */
ENCODE_JSON(Int64) {
    char buf[23];
    buf[0] = '\"';
    UA_UInt16 digits = itoaSigned(*src, buf + 1);
    buf[digits + 1] = '\"';
    UA_UInt16 length = (UA_UInt16)(digits + 2);

    if(ctx->pos + length > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, length);
    ctx->pos += length;
    return UA_STATUSCODE_GOOD;
}

ENCODE_JSON(Float) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "\"NaN\"");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "\"Infinity\"");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "\"-Infinity\"");
        len = strlen(buffer);
    } else {
        len = dtoa((UA_Double)*src, buffer);
    }

    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buffer, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

ENCODE_JSON(Double) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "\"NaN\"");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "\"Infinity\"");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "\"-Infinity\"");
        len = strlen(buffer);
    } else {
        len = dtoa(*src, buffer);
    }

    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buffer, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

static status
encodeJsonArray(CtxJson *ctx, const void *ptr, size_t length,
                const UA_DataType *type) {
    /* Null-arrays (length -1) are written as empty arrays '[]'.
     * TODO: Clarify the difference between length -1 and length 0 in JSON. */
    status ret = writeJsonArrStart(ctx);
    if(!ptr)
        return ret | writeJsonArrEnd(ctx, type);

    uintptr_t uptr = (uintptr_t)ptr;
    encodeJsonSignature encodeType = encodeJsonJumpTable[type->typeKind];
    UA_Boolean distinct = (type->typeKind > UA_DATATYPEKIND_DOUBLE);
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) {
        ret |= writeJsonBeforeElement(ctx, distinct);
        if(isNull((const void*)uptr, type))
            ret |= writeChars(ctx, "null", 4);
        else
            ret |= encodeType(ctx, (const void*)uptr, type);
        ctx->commaNeeded[ctx->depth] = true;
        uptr += type->memSize;
    }
    return ret | writeJsonArrEnd(ctx, type);
}

static const char hexmap[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

ENCODE_JSON(String) {
    if(!src->data)
        return writeChars(ctx, "null", 4);

    if(src->length == 0)
        return writeJsonQuote(ctx) | writeJsonQuote(ctx);

    UA_StatusCode ret = writeJsonQuote(ctx);

    const unsigned char *end = src->data + src->length;
    for(const unsigned char *pos = src->data; pos < end; pos++) {
        /* Skip to the first character that needs escaping */
        const unsigned char *start = pos;
        for(; pos < end; pos++) {
            if(*pos < ' ' || *pos == 127 || *pos == '\\' || *pos == '\"')
                break;
        }

        /* Write out the unescaped sequence */
        if(ctx->pos + (pos - start) > ctx->end)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        if(!ctx->calcOnly)
            memcpy(ctx->pos, start, (size_t)(pos - start));
        ctx->pos += pos - start;

        /* The unescaped sequence reached the end */
        if(pos == end)
            break;

        /* Write an escaped character */
        char *escape_text;
        char escape_buf[6];
        size_t escape_len = 2;
        switch(*pos) {
        case '\b': escape_text = "\\b"; break;
        case '\f': escape_text = "\\f"; break;
        case '\n': escape_text = "\\n"; break;
        case '\r': escape_text = "\\r"; break;
        case '\t': escape_text = "\\t"; break;
        default:
            escape_text = escape_buf;
            if(*pos >= ' ' && *pos != 127) {
                /* Escape \ or " */
                escape_buf[0] = '\\';
                escape_buf[1] = (char)*pos;
            } else {
                /* Unprintable characters need to be escaped */
                escape_buf[0] = '\\';
                escape_buf[1] = 'u';
                escape_buf[2] = '0';
                escape_buf[3] = '0';
                escape_buf[4] = hexmap[*pos >> 4];
                escape_buf[5] = hexmap[*pos & 0x0f];
                escape_len = 6;
            }
            break;
        }

        /* Enough space? */
        if(ctx->pos + escape_len > ctx->end)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

        /* Write the escaped character */
        if(!ctx->calcOnly)
            memcpy(ctx->pos, escape_text, escape_len);
        ctx->pos += escape_len;
    }

    return ret | writeJsonQuote(ctx);
}

ENCODE_JSON(ByteString) {
    if(!src->data)
        return writeChars(ctx, "null", 4);

    if(src->length == 0) {
        status retval = writeJsonQuote(ctx);
        retval |= writeJsonQuote(ctx);
        return retval;
    }

    status ret = writeJsonQuote(ctx);
    size_t flen = 0;
    unsigned char *ba64 = UA_base64(src->data, src->length, &flen);

    /* Not converted, no mem */
    if(!ba64)
        return UA_STATUSCODE_BADENCODINGERROR;

    if(ctx->pos + flen > ctx->end) {
        UA_free(ba64);
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    }

    /* Copy flen bytes to output stream. */
    if(!ctx->calcOnly)
        memcpy(ctx->pos, ba64, flen);
    ctx->pos += flen;

    /* Base64 result no longer needed */
    UA_free(ba64);

    return ret | writeJsonQuote(ctx);
}

/* Guid */
ENCODE_JSON(Guid) {
    if(ctx->pos + 38 > ctx->end) /* 36 + 2 (") */
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    status ret = writeJsonQuote(ctx);
    if(!ctx->calcOnly)
        UA_Guid_to_hex(src, ctx->pos, false);
    ctx->pos += 36;
    return ret | writeJsonQuote(ctx);
}

/* DateTime */
ENCODE_JSON(DateTime) {
    UA_Byte buffer[40];
    UA_String str = {40, buffer};
    encodeDateTime(*src, &str);
    return ENCODE_DIRECT_JSON(&str, String);
}

/* NodeId */
ENCODE_JSON(NodeId) {
    UA_String out = UA_STRING_NULL;
    UA_StatusCode ret = UA_NodeId_printEx(src, &out, ctx->namespaceMapping);
    ret |= ENCODE_DIRECT_JSON(&out, String);
    UA_String_clear(&out);
    return ret;
}

/* ExpandedNodeId */
ENCODE_JSON(ExpandedNodeId) {
    UA_String out = UA_STRING_NULL;
    UA_StatusCode ret = UA_ExpandedNodeId_printEx(src, &out, ctx->namespaceMapping,
                                                  ctx->serverUrisSize, ctx->serverUris);
    ret |= ENCODE_DIRECT_JSON(&out, String);
    UA_String_clear(&out);
    return ret;
}

/* LocalizedText */
ENCODE_JSON(LocalizedText) {
    status ret = writeJsonObjStart(ctx);
    ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALE);
    ret |= ENCODE_DIRECT_JSON(&src->locale, String);
    ret |= writeJsonKey(ctx, UA_JSONKEY_TEXT);
    ret |= ENCODE_DIRECT_JSON(&src->text, String);
    return ret | writeJsonObjEnd(ctx);
}

ENCODE_JSON(QualifiedName) {
    UA_String out = UA_STRING_NULL;
    UA_StatusCode ret = UA_QualifiedName_printEx(src, &out, ctx->namespaceMapping);
    ret |= ENCODE_DIRECT_JSON(&out, String);
    UA_String_clear(&out);
    return ret;
}

ENCODE_JSON(StatusCode) {
    const char *codename = UA_StatusCode_name(*src);
    UA_String statusDescription = UA_STRING((char*)(uintptr_t)codename);

    status ret = UA_STATUSCODE_GOOD;
    ret |= writeJsonObjStart(ctx);
    if(*src > UA_STATUSCODE_GOOD) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_CODE);
        ret |= ENCODE_DIRECT_JSON(src, UInt32);
        if(codename) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_SYMBOL);
            ret |= ENCODE_DIRECT_JSON(&statusDescription, String);
        }
    }
    ret |= writeJsonObjEnd(ctx);
    return ret;
}

/* ExtensionObject */
ENCODE_JSON(ExtensionObject) {
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return writeChars(ctx, "null", 4);

    /* Must have a type set if data is decoded */
    if(src->encoding != UA_EXTENSIONOBJECT_ENCODED_BYTESTRING &&
       src->encoding != UA_EXTENSIONOBJECT_ENCODED_XML &&
       !src->content.decoded.type)
        return UA_STATUSCODE_BADENCODINGERROR;

    status ret = writeJsonObjStart(ctx);

    /* Write the type NodeId */
    ret |= writeJsonKey(ctx, UA_JSONKEY_TYPEID);
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING ||
       src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML)
        ret |= ENCODE_DIRECT_JSON(&src->content.encoded.typeId, NodeId);
    else
        ret |= ENCODE_DIRECT_JSON(&src->content.decoded.type->typeId, NodeId);

    /* Write the encoding type and body if encoded */
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING ||
       src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML) {
        if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_ENCODING);
            ret |= writeChar(ctx, '1');
        } else {
            ret |= writeJsonKey(ctx, UA_JSONKEY_ENCODING);
            ret |= writeChar(ctx, '2');
        }
        ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
        ret |= ENCODE_DIRECT_JSON(&src->content.encoded.body, String);
        return ret | writeJsonObjEnd(ctx);
    }

    const UA_DataType *t = src->content.decoded.type;
    if(t->typeKind == UA_DATATYPEKIND_STRUCTURE) {
        /* Write structures in-situ.
         * TODO: Structures with optional fields and unions */
        ret |= encodeJsonStructureContent(ctx, src->content.decoded.data, t);
    } else {
        /* NON-STANDARD: The standard 1.05 doesn't let us print non-structure
         * types in ExtensionObjects (e.g. enums). Print them in the body. */
        ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
        ret |= encodeJsonJumpTable[t->typeKind](ctx, src->content.decoded.data, t);
    }

    return ret | writeJsonObjEnd(ctx);
}

/* Non-builtin types get wrapped in an ExtensionObject */
static status
encodeScalarJsonWrapExtensionObject(CtxJson *ctx, const UA_Variant *src) {
    const UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    const void *ptr = src->data;
    const UA_DataType *type = src->type;

    /* Set up a temporary ExtensionObject to wrap the data */
    UA_ExtensionObject eo;
    if(!isBuiltin) {
        UA_ExtensionObject_init(&eo);
        eo.encoding = UA_EXTENSIONOBJECT_DECODED;
        eo.content.decoded.type = src->type;
        eo.content.decoded.data = src->data;
        ptr = &eo;
        type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
    }

    return encodeJsonJumpTable[type->typeKind](ctx, ptr, type);
}

/* Non-builtin types get wrapped in an ExtensionObject */
static status
encodeArrayJsonWrapExtensionObject(CtxJson *ctx, const void *data,
                                   size_t size, const UA_DataType *type) {
    if(size > UA_INT32_MAX)
        return UA_STATUSCODE_BADENCODINGERROR;

    status ret = writeJsonArrStart(ctx);

    u16 memSize = type->memSize;
    const UA_Boolean isBuiltin = (type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(isBuiltin) {
        uintptr_t ptr = (uintptr_t)data;
        for(size_t i = 0; i < size && ret == UA_STATUSCODE_GOOD; ++i) {
            ret |= writeJsonArrElm(ctx, (const void*)ptr, type);
            ptr += memSize;
        }
    } else {
        /* Set up a temporary ExtensionObject to wrap the data */
        UA_ExtensionObject eo;
        UA_ExtensionObject_init(&eo);
        eo.encoding = UA_EXTENSIONOBJECT_DECODED;
        eo.content.decoded.type = type;
        eo.content.decoded.data = (void*)(uintptr_t)data;
        for(size_t i = 0; i < size && ret == UA_STATUSCODE_GOOD; ++i) {
            ret |= writeJsonArrElm(ctx, &eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
            eo.content.decoded.data = (void*)
                ((uintptr_t)eo.content.decoded.data + memSize);
        }
    }

    return ret | writeJsonArrEnd(ctx, type);
}

static UA_StatusCode
encodeVariantInner(CtxJson *ctx, const UA_Variant *src) {
    /* If type is 0 (NULL) the Variant contains a NULL value and the containing
     * JSON object shall be omitted or replaced by the JSON literal ‘null’ (when
     * an element of a JSON array). */
    if(!src->type)
        return UA_STATUSCODE_GOOD;

    /* Set the array type in the encoding mask */
    const bool isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL;
    const bool hasDimensions = isArray && src->arrayDimensionsSize > 1;

    /* Wrap the value in an ExtensionObject if not builtin. We cannot directly
     * encode a variant inside a variant (but arrays of variant are possible) */
    UA_Boolean wrapEO = (src->type->typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(src->type == &UA_TYPES[UA_TYPES_VARIANT] && !isArray)
        wrapEO = true;

    status ret = UA_STATUSCODE_GOOD;

    /* Write the type number */
    UA_UInt32 typeId = src->type->typeKind + 1;
    if(wrapEO)
        typeId = UA_TYPES[UA_TYPES_EXTENSIONOBJECT].typeKind + 1;
    ret |= writeJsonKey(ctx, UA_JSONKEY_TYPE);
    ret |= ENCODE_DIRECT_JSON(&typeId, UInt32);

    /* Write the value */
    ret |= writeJsonKey(ctx, UA_JSONKEY_VALUE);
    if(!isArray) {
        ret |= encodeScalarJsonWrapExtensionObject(ctx, src);
    } else {
        ret |= encodeArrayJsonWrapExtensionObject(ctx, src->data,
                                                  src->arrayLength, src->type);
    }

    /* Write the dimensions */
    if(hasDimensions) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_DIMENSIONS);
        ret |= encodeJsonArray(ctx, src->arrayDimensions, src->arrayDimensionsSize,
                               &UA_TYPES[UA_TYPES_UINT32]);
    }

    return ret;
}

ENCODE_JSON(Variant) {
    return writeJsonObjStart(ctx) | encodeVariantInner(ctx, src) | writeJsonObjEnd(ctx);
}

/* DataValue */
ENCODE_JSON(DataValue) {
    UA_Boolean hasValue = src->hasValue;
    UA_Boolean hasStatus = src->hasStatus;
    UA_Boolean hasSourceTimestamp = src->hasSourceTimestamp;
    UA_Boolean hasSourcePicoseconds = src->hasSourcePicoseconds;
    UA_Boolean hasServerTimestamp = src->hasServerTimestamp;
    UA_Boolean hasServerPicoseconds = src->hasServerPicoseconds;

    status ret = writeJsonObjStart(ctx);

    if(hasValue)
        ret |= encodeVariantInner(ctx, &src->value);

    if(hasStatus) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_STATUS);
        ret |= ENCODE_DIRECT_JSON(&src->status, StatusCode);
    }

    if(hasSourceTimestamp) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SOURCETIMESTAMP);
        ret |= ENCODE_DIRECT_JSON(&src->sourceTimestamp, DateTime);
    }

    if(hasSourcePicoseconds) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SOURCEPICOSECONDS);
        ret |= ENCODE_DIRECT_JSON(&src->sourcePicoseconds, UInt16);
    }

    if(hasServerTimestamp) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERTIMESTAMP);
        ret |= ENCODE_DIRECT_JSON(&src->serverTimestamp, DateTime);
    }

    if(hasServerPicoseconds) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERPICOSECONDS);
        ret |= ENCODE_DIRECT_JSON(&src->serverPicoseconds, UInt16);
    }

    return ret | writeJsonObjEnd(ctx);
}

/* DiagnosticInfo */
ENCODE_JSON(DiagnosticInfo) {
    status ret = writeJsonObjStart(ctx);

    if(src->hasSymbolicId) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SYMBOLICID);
        ret |= ENCODE_DIRECT_JSON(&src->symbolicId, Int32);
    }

    if(src->hasNamespaceUri) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACEURI);
        ret |= ENCODE_DIRECT_JSON(&src->namespaceUri, Int32);
    }

    if(src->hasLocalizedText) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALIZEDTEXT);
        ret |= ENCODE_DIRECT_JSON(&src->localizedText, Int32);
    }

    if(src->hasLocale) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALE);
        ret |= ENCODE_DIRECT_JSON(&src->locale, Int32);
    }

    if(src->hasAdditionalInfo) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_ADDITIONALINFO);
        ret |= ENCODE_DIRECT_JSON(&src->additionalInfo, String);
    }

    if(src->hasInnerStatusCode) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_INNERSTATUSCODE);
        ret |= ENCODE_DIRECT_JSON(&src->innerStatusCode, StatusCode);
    }

    if(src->hasInnerDiagnosticInfo && src->innerDiagnosticInfo) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_INNERDIAGNOSTICINFO);
        ret |= encodeJsonJumpTable[UA_DATATYPEKIND_DIAGNOSTICINFO]
            (ctx, src->innerDiagnosticInfo, NULL);
    }

    return ret | writeJsonObjEnd(ctx);
}

static status
encodeJsonStructureContent(CtxJson *ctx, const void *src, const UA_DataType *type) {
    uintptr_t ptr = (uintptr_t) src;
    u8 membersSize = type->membersSize;
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        if(m->memberName == NULL)
            return UA_STATUSCODE_BADENCODINGERROR;
        ret |= writeJsonKey(ctx, m->memberName);
        if(!m->isArray) {
            ptr += m->padding;
            size_t memSize = mt->memSize;
            ret |= encodeJsonJumpTable[mt->typeKind](ctx, (const void*) ptr, mt);
            ptr += memSize;
        } else {
            ptr += m->padding;
            const size_t length = *((const size_t*) ptr);
            ptr += sizeof (size_t);
            ret |= encodeJsonArray(ctx, *(void * const *)ptr, length, mt);
            ptr += sizeof (void*);
        }
    }
    return ret;
}

static status
encodeJsonStructure(CtxJson *ctx, const void *src, const UA_DataType *type) {
    return writeJsonObjStart(ctx) | encodeJsonStructureContent(ctx, src, type) | writeJsonObjEnd(ctx);
}

static status
encodeJsonNotImplemented(const void *src, const UA_DataType *type, CtxJson *ctx) {
    (void) src, (void) type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const encodeJsonSignature encodeJsonJumpTable[UA_DATATYPEKINDS] = {
    (encodeJsonSignature)Boolean_encodeJson,
    (encodeJsonSignature)SByte_encodeJson, /* SByte */
    (encodeJsonSignature)Byte_encodeJson,
    (encodeJsonSignature)Int16_encodeJson, /* Int16 */
    (encodeJsonSignature)UInt16_encodeJson,
    (encodeJsonSignature)Int32_encodeJson, /* Int32 */
    (encodeJsonSignature)UInt32_encodeJson,
    (encodeJsonSignature)Int64_encodeJson, /* Int64 */
    (encodeJsonSignature)UInt64_encodeJson,
    (encodeJsonSignature)Float_encodeJson,
    (encodeJsonSignature)Double_encodeJson,
    (encodeJsonSignature)String_encodeJson,
    (encodeJsonSignature)DateTime_encodeJson, /* DateTime */
    (encodeJsonSignature)Guid_encodeJson,
    (encodeJsonSignature)ByteString_encodeJson, /* ByteString */
    (encodeJsonSignature)String_encodeJson, /* XmlElement */
    (encodeJsonSignature)NodeId_encodeJson,
    (encodeJsonSignature)ExpandedNodeId_encodeJson,
    (encodeJsonSignature)StatusCode_encodeJson, /* StatusCode */
    (encodeJsonSignature)QualifiedName_encodeJson, /* QualifiedName */
    (encodeJsonSignature)LocalizedText_encodeJson,
    (encodeJsonSignature)ExtensionObject_encodeJson,
    (encodeJsonSignature)DataValue_encodeJson,
    (encodeJsonSignature)Variant_encodeJson,
    (encodeJsonSignature)DiagnosticInfo_encodeJson,
    (encodeJsonSignature)encodeJsonNotImplemented, /* Decimal */
    (encodeJsonSignature)Int32_encodeJson, /* Enum */
    (encodeJsonSignature)encodeJsonStructure,
    (encodeJsonSignature)encodeJsonNotImplemented, /* Structure with optional fields */
    (encodeJsonSignature)encodeJsonNotImplemented, /* Union */
    (encodeJsonSignature)encodeJsonNotImplemented /* BitfieldCluster */
};

UA_StatusCode
UA_encodeJson(const void *src, const UA_DataType *type, UA_ByteString *outBuf,
              const UA_EncodeJsonOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate buffer */
    UA_Boolean allocated = false;
    status res = UA_STATUSCODE_GOOD;
    if(outBuf->length == 0) {
        size_t len = UA_calcSizeJson(src, type, options);
        res = UA_ByteString_allocBuffer(outBuf, len);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        allocated = true;
    }

    /* Set up the context */
    CtxJson ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = outBuf->data;
    ctx.end = &outBuf->data[outBuf->length];
    ctx.depth = 0;
    ctx.calcOnly = false;
    ctx.useReversible = true; /* default */
    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.useReversible = options->useReversible;
        ctx.prettyPrint = options->prettyPrint;
        ctx.unquotedKeys = options->unquotedKeys;
        ctx.stringNodeIds = options->stringNodeIds;
    }

    /* Encode */
    res = encodeJsonJumpTable[type->typeKind](&ctx, src, type);

    /* Clean up */
    if(res == UA_STATUSCODE_GOOD)
        outBuf->length = (size_t)((uintptr_t)ctx.pos - (uintptr_t)outBuf->data);
    else if(allocated)
        UA_ByteString_clear(outBuf);
    return res;
}

UA_StatusCode
UA_print(const void *p, const UA_DataType *type, UA_String *output) {
    if(!p || !type || !output)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_EncodeJsonOptions options;
    memset(&options, 0, sizeof(UA_EncodeJsonOptions));
    options.useReversible = true;
    options.prettyPrint = true;
    options.unquotedKeys = true;
    options.stringNodeIds = true;
    return UA_encodeJson(p, type, output, &options);
}

/************/
/* CalcSize */
/************/

size_t
UA_calcSizeJson(const void *src, const UA_DataType *type,
                const UA_EncodeJsonOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Set up the context */
    CtxJson ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = NULL;
    ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
    ctx.depth = 0;
    ctx.useReversible = true; /* default */
    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.useReversible = options->useReversible;
        ctx.prettyPrint = options->prettyPrint;
        ctx.unquotedKeys = options->unquotedKeys;
        ctx.stringNodeIds = options->stringNodeIds;
    }

    ctx.calcOnly = true;

    /* Encode */
    status ret = encodeJsonJumpTable[type->typeKind](&ctx, src, type);
    if(ret != UA_STATUSCODE_GOOD)
        return 0;
    return (size_t)ctx.pos;
}

/**********/
/* Decode */
/**********/

#define GET_TOKEN                                                       \
    size_t tokenSize = getTokenLength(&ctx->tokens[ctx->index]);        \
    const char* tokenData = &ctx->json5[ctx->tokens[ctx->index].start]; \
    do {} while(0)

#define CHECK_TOKEN_BOUNDS do {                   \
    if(ctx->index >= ctx->tokensSize)             \
        return UA_STATUSCODE_BADDECODINGERROR;    \
    } while(0)

#define CHECK_NUMBER do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_NUMBER) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_BOOL do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_BOOL) {      \
        return UA_STATUSCODE_BADDECODINGERROR;         \
    }} while(0)

#define CHECK_STRING do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_STRING) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_OBJECT do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_NULL_SKIP do {                         \
    if(currentTokenType(ctx) == CJ5_TOKEN_NULL) {    \
        ctx->index++;                                \
        return UA_STATUSCODE_GOOD;                   \
    }} while(0)

/* Forward declarations*/
#define DECODE_JSON(TYPE) static status                   \
    TYPE##_decodeJson(ParseCtx *ctx, UA_##TYPE *dst,      \
                      const UA_DataType *type)

/* If ctx->index points to the beginning of an object, move the index to the
 * next token after this object. Attention! The index can be moved after the
 * last parsed token. So the array length has to be checked afterwards. */
static void
skipObject(ParseCtx *ctx) {
    unsigned int end = ctx->tokens[ctx->index].end;
    do {
        ctx->index++;
    } while(ctx->index < ctx->tokensSize &&
            ctx->tokens[ctx->index].start < end);
}

static status
Array_decodeJson(ParseCtx *ctx, void **dst, const UA_DataType *type);

static status
Variant_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void *p, const UA_DataType *type);

static UA_SByte
jsoneq(const char *json, const cj5_token *tok, const char *searchKey) {
    /* TODO: necessary?
       if(json == NULL
            || tok == NULL
            || searchKey == NULL) {
        return -1;
    } */

    size_t len = getTokenLength(tok);
    if(tok->type == CJ5_TOKEN_STRING &&
       strlen(searchKey) ==  len &&
       strncmp(json + tok->start, (const char*)searchKey, len) == 0)
        return 0;

    return -1;
}

DECODE_JSON(Boolean) {
    CHECK_TOKEN_BOUNDS;
    CHECK_BOOL;
    GET_TOKEN;

    if(tokenSize == 4 &&
       (tokenData[0] | 32) == 't' && (tokenData[1] | 32) == 'r' &&
       (tokenData[2] | 32) == 'u' && (tokenData[3] | 32) == 'e') {
        *dst = true;
    } else if(tokenSize == 5 &&
              (tokenData[0] | 32) == 'f' && (tokenData[1] | 32) == 'a' &&
              (tokenData[2] | 32) == 'l' && (tokenData[3] | 32) == 's' &&
              (tokenData[4] | 32) == 'e') {
        *dst = false;
    } else {
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parseUnsignedInteger(const char *tokenData, size_t tokenSize, UA_UInt64 *dst) {
    size_t len = parseUInt64(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parseSignedInteger(const char *tokenData, size_t tokenSize, UA_Int64 *dst) {
    size_t len = parseInt64(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Byte) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_BYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Byte)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt16) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_UInt16)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt32) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_UInt32)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt64) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, dst);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(SByte) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_SBYTE_MIN || out > UA_SBYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_SByte)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int16) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT16_MIN || out > UA_INT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Int16)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int32) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT32_MIN || out > UA_INT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Int32)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int64) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, dst);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

/* Either a STRING or NUMBER token */
DECODE_JSON(Double) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    /* https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/
     * Maximum digit counts for select IEEE floating-point formats: 1074
     * Sanity check.
     */
    if(tokenSize > 2000)
        return UA_STATUSCODE_BADDECODINGERROR;

    cj5_token_type tokenType = currentTokenType(ctx);

    /* It could be a String with Nan, Infinity */
    if(tokenType == CJ5_TOKEN_STRING) {
        ctx->index++;

        if(tokenSize == 8 && memcmp(tokenData, "Infinity", 8) == 0) {
            *dst = INFINITY;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 9 && memcmp(tokenData, "-Infinity", 9) == 0) {
            /* workaround an MSVC 2013 issue */
            *dst = -INFINITY;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 3 && memcmp(tokenData, "NaN", 3) == 0) {
            *dst = NAN;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 4 && memcmp(tokenData, "-NaN", 4) == 0) {
            *dst = NAN;
            return UA_STATUSCODE_GOOD;
        }

        return UA_STATUSCODE_BADDECODINGERROR;
    }

    if(tokenType != CJ5_TOKEN_NUMBER)
        return UA_STATUSCODE_BADDECODINGERROR;

    size_t len = parseDouble(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Float) {
    UA_Double v = 0.0;
    UA_StatusCode res = Double_decodeJson(ctx, &v, NULL);
    *dst = (UA_Float)v;
    return res;
}

DECODE_JSON(Guid) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* Use the existing parsing routine if available */
    UA_String str = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
    ctx->index++;
    return UA_Guid_parse(dst, str);
}

DECODE_JSON(String) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;
    (void)tokenData;

    /* Empty string? */
    if(tokenSize == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
        ctx->index++;
        return UA_STATUSCODE_GOOD;
    }

    /* The decoded utf8 is at most of the same length as the source string */
    char *outBuf = (char*)UA_malloc(tokenSize+1);
    if(!outBuf)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode the string */
    cj5_result r;
    r.tokens = ctx->tokens;
    r.num_tokens = (unsigned int)ctx->tokensSize;
    r.json5 = ctx->json5;
    unsigned int len = 0;
    cj5_error_code err = cj5_get_str(&r, (unsigned int)ctx->index, outBuf, &len);
    if(err != CJ5_ERROR_NONE) {
        UA_free(outBuf);
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Set the output */
    dst->length = len;
    if(dst->length > 0) {
        dst->data = (UA_Byte*)outBuf;
    } else {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        UA_free(outBuf);
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(ByteString) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* Empty bytestring? */
    if(tokenSize == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
    } else {
        size_t flen = 0;
        unsigned char* unB64 =
            UA_unbase64((const unsigned char*)tokenData, tokenSize, &flen);
        if(unB64 == 0)
            return UA_STATUSCODE_BADDECODINGERROR;
        dst->data = (u8*)unB64;
        dst->length = flen;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(LocalizedText) {
    CHECK_OBJECT;

    DecodeEntry entries[2] = {
        {UA_JSONKEY_LOCALE, &dst->locale, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_TEXT, &dst->text, NULL, false, &UA_TYPES[UA_TYPES_STRING]}
    };

    return decodeFields(ctx, entries, 2);
}

DECODE_JSON(QualifiedName) {
    UA_String str;
    UA_String_init(&str);
    status res = String_decodeJson(ctx, &str, NULL);
    if(res == UA_STATUSCODE_GOOD)
        res = UA_QualifiedName_parseEx(dst, str, ctx->namespaceMapping);
    UA_String_clear(&str);
    return res;
}

status
lookAheadForKey(ParseCtx *ctx, const char *key, size_t *resultIndex) {
    /* The current index must point to the beginning of an object.
     * This has to be ensured by the caller. */
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_OBJECT);

    status ret = UA_STATUSCODE_BADNOTFOUND;
    size_t oldIndex = ctx->index; /* Save index for later restore */
    unsigned int end = ctx->tokens[ctx->index].end;
    ctx->index++; /* Move to the first key */
    while(ctx->index < ctx->tokensSize &&
          ctx->tokens[ctx->index].start < end) {
        /* Key must be a string */
        UA_assert(currentTokenType(ctx) == CJ5_TOKEN_STRING);

        /* Move index to the value */
        ctx->index++;

        /* Value for the key must exist */
        UA_assert(ctx->index < ctx->tokensSize);

        /* Compare the key (previous index) */
        if(jsoneq(ctx->json5, &ctx->tokens[ctx->index-1], key) == 0) {
            *resultIndex = ctx->index; /* Point result to the current index */
            ret = UA_STATUSCODE_GOOD;
            break;
        }

        skipObject(ctx); /* Jump over the value (can also be an array or object) */
    }
    ctx->index = oldIndex; /* Restore the old index */
    return ret;
}

DECODE_JSON(NodeId) {
    UA_String str;
    UA_String_init(&str);
    status res = String_decodeJson(ctx, &str, NULL);
    if(res == UA_STATUSCODE_GOOD)
        res = UA_NodeId_parseEx(dst, str, ctx->namespaceMapping);
    UA_String_clear(&str);
    return res;
}

DECODE_JSON(ExpandedNodeId) {
    UA_String str;
    UA_String_init(&str);
    status res = String_decodeJson(ctx, &str, NULL);
    if(res == UA_STATUSCODE_GOOD)
        res = UA_ExpandedNodeId_parseEx(dst, str, ctx->namespaceMapping,
                                        ctx->serverUrisSize, ctx->serverUris);
    UA_String_clear(&str);
    return res;
}

DECODE_JSON(DateTime) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* The last character has to be 'Z'. We can omit some length checks later on
     * because we know the atoi functions stop before the 'Z'. */
    if(tokenSize == 0 || tokenData[tokenSize-1] != 'Z')
        return UA_STATUSCODE_BADDECODINGERROR;

    struct musl_tm dts;
    memset(&dts, 0, sizeof(dts));

    size_t pos = 0;
    size_t len;

    /* Parse the year. The ISO standard asks for four digits. But we accept up
     * to five with an optional plus or minus in front due to the range of the
     * DateTime 64bit integer. But in that case we require the year and the
     * month to be separated by a '-'. Otherwise we cannot know where the month
     * starts. */
    if(tokenData[0] == '-' || tokenData[0] == '+')
        pos++;
    UA_Int64 year = 0;
    len = parseInt64(&tokenData[pos], 5, &year);
    pos += len;
    if(len != 4 && tokenData[pos] != '-')
        return UA_STATUSCODE_BADDECODINGERROR;
    if(tokenData[0] == '-')
        year = -year;
    dts.tm_year = (UA_Int16)year - 1900;
    if(tokenData[pos] == '-')
        pos++;

    /* Parse the month */
    UA_UInt64 month = 0;
    len = parseUInt64(&tokenData[pos], 2, &month);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_mon = (UA_UInt16)month - 1;
    if(tokenData[pos] == '-')
        pos++;

    /* Parse the day and check the T between date and time */
    UA_UInt64 day = 0;
    len = parseUInt64(&tokenData[pos], 2, &day);
    pos += len;
    UA_CHECK(len == 2 || tokenData[pos] != 'T',
             return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_mday = (UA_UInt16)day;
    pos++;

    /* Parse the hour */
    UA_UInt64 hour = 0;
    len = parseUInt64(&tokenData[pos], 2, &hour);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_hour = (UA_UInt16)hour;
    if(tokenData[pos] == ':')
        pos++;

    /* Parse the minute */
    UA_UInt64 min = 0;
    len = parseUInt64(&tokenData[pos], 2, &min);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_min = (UA_UInt16)min;
    if(tokenData[pos] == ':')
        pos++;

    /* Parse the second */
    UA_UInt64 sec = 0;
    len = parseUInt64(&tokenData[pos], 2, &sec);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_sec = (UA_UInt16)sec;

    /* Compute the seconds since the Unix epoch */
    long long sinceunix = musl_tm_to_secs(&dts);

    /* Are we within the range that can be represented? */
    long long sinceunix_min =
        (long long)(UA_INT64_MIN / UA_DATETIME_SEC) -
        (long long)(UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC) -
        (long long)1; /* manual correction due to rounding */
    long long sinceunix_max = (long long)
        ((UA_INT64_MAX - UA_DATETIME_UNIX_EPOCH) / UA_DATETIME_SEC);
    if(sinceunix < sinceunix_min || sinceunix > sinceunix_max)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Convert to DateTime. Add or subtract one extra second here to prevent
     * underflow/overflow. This is reverted once the fractional part has been
     * added. */
    sinceunix -= (sinceunix > 0) ? 1 : -1;
    UA_DateTime dt = (UA_DateTime)
        (sinceunix + (UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC)) * UA_DATETIME_SEC;

    /* Parse the fraction of the second if defined */
    if(tokenData[pos] == ',' || tokenData[pos] == '.') {
        pos++;
        double frac = 0.0;
        double denom = 0.1;
        while(pos < tokenSize &&
              tokenData[pos] >= '0' && tokenData[pos] <= '9') {
            frac += denom * (tokenData[pos] - '0');
            denom *= 0.1;
            pos++;
        }
        frac += 0.00000005; /* Correct rounding when converting to integer */
        dt += (UA_DateTime)(frac * UA_DATETIME_SEC);
    }

    /* Remove the underflow/overflow protection (see above) */
    if(sinceunix > 0) {
        if(dt > UA_INT64_MAX - UA_DATETIME_SEC)
            return UA_STATUSCODE_BADDECODINGERROR;
        dt += UA_DATETIME_SEC;
    } else {
        if(dt < UA_INT64_MIN + UA_DATETIME_SEC)
            return UA_STATUSCODE_BADDECODINGERROR;
        dt -= UA_DATETIME_SEC;
    }

    /* We must be at the end of the string (ending with 'Z' as checked above) */
    if(pos != tokenSize - 1)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = dt;

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(StatusCode) {
    CHECK_OBJECT;
    DecodeEntry entries[2] = {
        {UA_JSONKEY_CODE, dst, NULL, false, &UA_TYPES[UA_TYPES_UINT32]},
        {UA_JSONKEY_SYMBOL, NULL, NULL, false, NULL}
    };
    return decodeFields(ctx, entries, 2);
}

/* Get type type encoded by the ExtensionObject at ctx->index.
 * Returns NULL if that fails (type unknown or otherwise). */
static const UA_DataType *
getExtensionObjectType(ParseCtx *ctx) {
    if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT)
        return NULL;

    /* Get the type NodeId index */
    size_t typeIdIndex = 0;
    UA_StatusCode ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &typeIdIndex);
    if(ret != UA_STATUSCODE_GOOD)
        return NULL;

    size_t oldIndex = ctx->index;
    ctx->index = (UA_UInt16)typeIdIndex;

    /* Decode the type NodeId */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    ret = NodeId_decodeJson(ctx, &typeId, &UA_TYPES[UA_TYPES_NODEID]);
    ctx->index = oldIndex;
    if(ret != UA_STATUSCODE_GOOD) {
        UA_NodeId_clear(&typeId); /* We don't have the global cleanup */
        return NULL;
    }

    /* Lookup an return */
    const UA_DataType *type = UA_findDataTypeWithCustom(&typeId, ctx->customTypes);
    UA_NodeId_clear(&typeId);
    return type;
}

/* Check if all array members are ExtensionObjects of the same type. Return this
 * type or NULL. */
static const UA_DataType *
getArrayUnwrapType(ParseCtx *ctx) {
    UA_assert(ctx->tokens[ctx->index].type == CJ5_TOKEN_ARRAY);

    /* Return early for empty arrays */
    size_t length = (size_t)ctx->tokens[ctx->index].size;
    if(length == 0)
        return NULL;

    /* Save the original index and go to the first array member */
    size_t oldIndex = ctx->index;
    ctx->index++;

    /* Lookup the type for the first array member */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    const UA_DataType *typeOfBody = getExtensionObjectType(ctx);
    if(!typeOfBody) {
        ctx->index = oldIndex; /* Restore the index */
        return NULL;
    }

    /* Get the TypeId encoding for faster comparison below.
     * Cannot fail as getExtensionObjectType already looked this up. */
    size_t typeIdIndex = 0;
    UA_StatusCode ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &typeIdIndex);
    (void)ret;
    UA_assert(ret == UA_STATUSCODE_GOOD);
    const char* typeIdData = &ctx->json5[ctx->tokens[typeIdIndex].start];
    size_t typeIdSize = getTokenLength(&ctx->tokens[typeIdIndex]);

    /* Loop over all members and check whether they can be unwrapped. Don't skip
     * the first member. We still haven't checked the encoding type. */
    for(size_t i = 0; i < length; i++) {
        /* Array element must be an object */
        if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Check for non-JSON encoding */
        size_t encIndex = 0;
        ret = lookAheadForKey(ctx, UA_JSONKEY_ENCODING, &encIndex);
        if(ret == UA_STATUSCODE_GOOD) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Get the type NodeId index */
        size_t memberTypeIdIndex = 0;
        ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &memberTypeIdIndex);
        if(ret != UA_STATUSCODE_GOOD) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Is it the same type? Compare raw NodeId string */
        const char* memberTypeIdData = &ctx->json5[ctx->tokens[memberTypeIdIndex].start];
        size_t memberTypeIdSize = getTokenLength(&ctx->tokens[memberTypeIdIndex]);
        if(typeIdSize != memberTypeIdSize ||
           memcmp(typeIdData, memberTypeIdData, typeIdSize) != 0) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Skip to the next array member */
        skipObject(ctx);
    }

    ctx->index = oldIndex; /* Restore the index */
    return typeOfBody;
}

static status
Array_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void **dst, const UA_DataType *type) {
    size_t *size_ptr = (size_t*) dst - 1; /* Save the length pointer of the array */
    size_t length = (size_t)ctx->tokens[ctx->index].size;

    /* Known from the previous unwrapping-check */
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_ARRAY);
    UA_assert(length > 0);

    ctx->index++; /* Go to first array member */

    /* Allocate memory */
    *dst = UA_calloc(length, type->memSize);
    if(*dst == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode array members */
    status ret = UA_STATUSCODE_GOOD;
    uintptr_t ptr = (uintptr_t)*dst;
    for(size_t i = 0; i < length; i++) {
        UA_assert(ctx->tokens[ctx->index].type == CJ5_TOKEN_OBJECT);
        if(type->typeKind == UA_DATATYPEKIND_STRUCTURE) {
            /* Decode structure in-situ in the ExtensionObject */
            ret = decodeJsonStructure(ctx, (void*)ptr, type);
        } else {
            /* Get the body field and decode it */
            DecodeEntry entries[3] = {
                {UA_JSONKEY_TYPEID, NULL, NULL, false, NULL},
                {UA_JSONKEY_BODY, (void*)ptr, NULL, false, type},
                {UA_JSONKEY_ENCODING, NULL, NULL, false, NULL}
            };
            ret = decodeFields(ctx, entries, 3);
        }
        if(ret != UA_STATUSCODE_GOOD) {
            UA_Array_delete(*dst, i+1, type);
            *dst = NULL;
            return ret;
        }
        ptr += type->memSize;
    }

    *size_ptr = length; /* All good, set the size */
    return UA_STATUSCODE_GOOD;
}

static status
decodeJSONVariant(ParseCtx *ctx, UA_Variant *dst) {
    /* Empty variant == null */
    if(ctx->tokens[ctx->index].size == 0) {
        ctx->index++;
        return UA_STATUSCODE_GOOD;
    }

    /* Search the value field */
    size_t valueIndex = 0;
    lookAheadForKey(ctx, UA_JSONKEY_VALUE, &valueIndex);

    /* Search for the dimensions field */
    size_t dimIndex = 0;
    lookAheadForKey(ctx, UA_JSONKEY_DIMENSIONS, &dimIndex);

    /* Parse the type kind */
    size_t typeIndex = 0;
    lookAheadForKey(ctx, UA_JSONKEY_TYPE, &typeIndex);
    if(typeIndex == 0 || ctx->tokens[typeIndex].type != CJ5_TOKEN_NUMBER)
        return UA_STATUSCODE_BADDECODINGERROR;
    UA_UInt64 typeKind = 0;
    size_t len = parseUInt64(&ctx->json5[ctx->tokens[typeIndex].start],
                             getTokenLength(&ctx->tokens[typeIndex]), &typeKind);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Shift to get the datatype index. The type must be a builtin data type.
     * All not-builtin types are wrapped in an ExtensionObject. */
    typeKind--;
    if(typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO)
        return UA_STATUSCODE_BADDECODINGERROR;
    const UA_DataType *type = &UA_TYPES[typeKind];

    /* Value is an array? */
    UA_Boolean isArray =
        (valueIndex > 0 && ctx->tokens[valueIndex].type == CJ5_TOKEN_ARRAY);

    /* Decode the value */
    status res = UA_STATUSCODE_GOOD;
    size_t beginIndex = ctx->index;
    ctx->index = valueIndex;
    ctx->depth++;
    if(!isArray) {
        /* Scalar with dimensions -> error */
        if(dimIndex > 0) {
            res = UA_STATUSCODE_BADDECODINGERROR;
            goto out;
        }

        /* A variant cannot contain a variant. But it can contain an array of
         * variants */
        if(type->typeKind == UA_DATATYPEKIND_VARIANT) {
            res = UA_STATUSCODE_BADDECODINGERROR;
            goto out;
        }

        /* Decode a value wrapped in an ExtensionObject */
        if(valueIndex > 0 && type->typeKind == UA_DATATYPEKIND_EXTENSIONOBJECT) {
            res = Variant_decodeJsonUnwrapExtensionObject(ctx, dst, NULL);
            goto out;
        }

        /* Allocate memory for the value */
        dst->data = UA_new(type);
        if(!dst->data) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
            goto out;
        }
        dst->type = type;

        /* Decode the value */
        if(valueIndex > 0 && ctx->tokens[valueIndex].type != CJ5_TOKEN_NULL)
            res = decodeJsonJumpTable[type->typeKind](ctx, dst->data, type);
    } else {
        /* Decode an array. Try to unwrap ExtensionObjects in the array. The
         * members must all have the same type. */
        const UA_DataType *unwrapType = NULL;
        if(type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
            unwrapType = getArrayUnwrapType(ctx);
        if(unwrapType) {
            dst->type = unwrapType;
            res = Array_decodeJsonUnwrapExtensionObject(ctx, &dst->data, unwrapType);
        } else {
            dst->type = type;
            res = Array_decodeJson(ctx, &dst->data, type);
        }

        /* Decode array dimensions */
        if(dimIndex > 0) {
            ctx->index = dimIndex;
            res |= Array_decodeJson(ctx, (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);

            /* Help clang-analyzer */
            UA_assert(dst->arrayDimensionsSize == 0 || dst->arrayDimensions);

            /* Validate the dimensions */
            size_t total = 1;
            for(size_t i = 0; i < dst->arrayDimensionsSize; i++)
                total *= dst->arrayDimensions[i];
            if(total != dst->arrayLength)
                res |= UA_STATUSCODE_BADDECODINGERROR;

            /* Only keep >= 2 dimensions */
            if(dst->arrayDimensionsSize == 1) {
                UA_free(dst->arrayDimensions);
                dst->arrayDimensions = NULL;
                dst->arrayDimensionsSize = 0;
            }
        }
    }

 out:
    ctx->index = beginIndex;
    skipObject(ctx);
    ctx->depth--;
    return res;
}

DECODE_JSON(Variant) {
    CHECK_NULL_SKIP; /* Treat null as an empty variant */
    CHECK_OBJECT;
    return decodeJSONVariant(ctx, dst);
}

DECODE_JSON(DataValue) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DataValue */
    CHECK_OBJECT;

    /* Decode the Variant in-situ */
    size_t beginIndex = ctx->index;
    status ret = decodeJSONVariant(ctx, &dst->value);
    ctx->index = beginIndex;
    dst->hasValue = (dst->value.type != NULL);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Decode the other members (skip the Variant members) */
    DecodeEntry entries[8] = {
        {UA_JSONKEY_TYPE, NULL, NULL, false, NULL},
        {UA_JSONKEY_VALUE, NULL, NULL, false, NULL},
        {UA_JSONKEY_DIMENSIONS, NULL, NULL, false, NULL},
        {UA_JSONKEY_STATUS, &dst->status, NULL, false, &UA_TYPES[UA_TYPES_STATUSCODE]},
        {UA_JSONKEY_SOURCETIMESTAMP, &dst->sourceTimestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
        {UA_JSONKEY_SOURCEPICOSECONDS, &dst->sourcePicoseconds, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
        {UA_JSONKEY_SERVERTIMESTAMP, &dst->serverTimestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
        {UA_JSONKEY_SERVERPICOSECONDS, &dst->serverPicoseconds, NULL, false, &UA_TYPES[UA_TYPES_UINT16]}
    };

    ret = decodeFields(ctx, entries, 8);
    dst->hasStatus = entries[3].found;
    dst->hasSourceTimestamp = entries[4].found;
    dst->hasSourcePicoseconds = entries[5].found;
    dst->hasServerTimestamp = entries[6].found;
    dst->hasServerPicoseconds = entries[7].found;
    return ret;
}

/* Move the entire current token into the target bytestring */
static UA_StatusCode
tokenToByteString(ParseCtx *ctx, UA_ByteString *p) {
    GET_TOKEN;
    UA_StatusCode res = UA_ByteString_allocBuffer(p, tokenSize);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    memcpy(p->data, tokenData, tokenSize);
    skipObject(ctx);
    return UA_STATUSCODE_GOOD;
}

/* Remove an unwanted field from an object. The original data is in ctx->json5.
 * ctx->index points to the beginning of the object. That object was copied
 * verbatim into the encoding ByteString. tokenIndex points to the field (after
 * the field name) that shall be removed. */
static void
removeFieldFromEncoding(ParseCtx *ctx, UA_ByteString *encoding,
                        size_t parentIndex, size_t tokenIndex) {
    /* Which part of the encoding to cut out */
    unsigned objStart = ctx->tokens[parentIndex].start;
    unsigned objEnd = ctx->tokens[parentIndex].end;
    unsigned start = ctx->tokens[tokenIndex-1].start;
    unsigned end = ctx->tokens[tokenIndex].end + 1; /* One char after */

    UA_Boolean haveBefore = (parentIndex < tokenIndex - 2);
    if(haveBefore) {
        /* Find where the previous token ended. This also removes the comma
         * between the previous and the current element. */
        for(size_t i = parentIndex + 2; i < tokenIndex - 1; i++) {
            if(ctx->tokens[i].end + 1 > start)
                start = ctx->tokens[i].end + 1;
        }
        if(ctx->json5[start] == '"' || ctx->json5[start] == '\'')
            start++;
    } else {
        /* No previous element. Remove the quoation marks of the field name. */
        start = ctx->tokens[tokenIndex-1].start;
        if(start > 0 && (ctx->json5[start-1] == '"' || ctx->json5[start-1] == '\''))
            start--;

        /* Find the beginning of the next field in the object.
         * This removes the comma after the current field. */
        size_t oldIndex = ctx->index;
        ctx->index = tokenIndex;
        skipObject(ctx);
        if(ctx->index < ctx->tokensSize && ctx->tokens[ctx->index].start < objEnd) {
            end = ctx->tokens[ctx->index].start;
            if(ctx->json5[end-1] == '"' || ctx->json5[end-1] == '\'')
                end--;
        }
        ctx->index = oldIndex;
    }

    UA_assert(end > start);
    UA_assert(start > objStart);

    /* Move the offset from ctx->json5 to encoding->data */
    start -= objStart;
    end -= objStart;

    UA_assert(end <= encoding->length);

    /* Cut out the field we want to remove */
    size_t after_len = encoding->length - end;
    memmove(encoding->data + start, encoding->data + end, after_len);
    encoding->length -= (end - start);
}

DECODE_JSON(ExtensionObject) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DataValue */
    CHECK_OBJECT;

    /* Empty object -> Null ExtensionObject */
    if(ctx->tokens[ctx->index].size == 0) {
        ctx->index++; /* Skip the empty ExtensionObject */
        return UA_STATUSCODE_GOOD;
    }

    /* Store the index where the ExtensionObject begins */
    size_t beginIndex = ctx->index;

    /* Search for non-JSON encoding */
    UA_UInt64 encoding = 0;
    size_t encIndex = 0;
    status ret = lookAheadForKey(ctx, UA_JSONKEY_ENCODING, &encIndex);
    if(ret == UA_STATUSCODE_GOOD) {
        const char *extObjEncoding = &ctx->json5[ctx->tokens[encIndex].start];
        size_t len = parseUInt64(extObjEncoding, getTokenLength(&ctx->tokens[encIndex]), &encoding);
        if(len == 0 || encoding > 2)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Get the type NodeId index */
    size_t typeIdIndex = 0;
    ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &typeIdIndex);
    if(ret != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Decode the type NodeId */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    ctx->index = (UA_UInt16)typeIdIndex;
    ret = NodeId_decodeJson(ctx, &typeId, &UA_TYPES[UA_TYPES_NODEID]);
    ctx->index = beginIndex;
    if(ret != UA_STATUSCODE_GOOD) {
        UA_NodeId_clear(&typeId); /* We don't have the global cleanup */
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Lookup the type */
    type = UA_findDataTypeWithCustom(&typeId, ctx->customTypes);

    /* Unknown body type */
    if(!type) {
        /* FIXME: We need UA_EXTENSIONOBJECT_ENCODED_JSON when we parse an
         * unknown type in JSON. But it is not defined in the standard. */
        dst->encoding = (encoding != 2) ?
            UA_EXTENSIONOBJECT_ENCODED_BYTESTRING :
            UA_EXTENSIONOBJECT_ENCODED_XML;
        dst->content.encoded.typeId = typeId;

        /* Get the body field index */
        size_t bodyIndex = 0;
        ret = lookAheadForKey(ctx, UA_JSONKEY_BODY, &bodyIndex);
        if(ret != UA_STATUSCODE_GOOD) {
            /* Only JSON structures can be encoded in-situ */
            if(encoding != 0)
                return UA_STATUSCODE_BADDECODINGERROR;

            /* Extract the entire ExtensionObject object as the body */
            size_t parentIndex = ctx->index;
            ret = tokenToByteString(ctx, &dst->content.encoded.body);
            if(ret != UA_STATUSCODE_GOOD)
                return ret;

            /* Remove the UaEncoding and UaTypeId field from the encoding.
             * Remove the later field first. */
            if(encIndex != 0 && encIndex > typeIdIndex)
                removeFieldFromEncoding(ctx, &dst->content.encoded.body, parentIndex, encIndex);
            removeFieldFromEncoding(ctx, &dst->content.encoded.body, parentIndex, typeIdIndex);
            if(encIndex != 0 && encIndex < typeIdIndex)
                removeFieldFromEncoding(ctx, &dst->content.encoded.body, parentIndex, encIndex);

            return UA_STATUSCODE_GOOD;
        }

        ctx->index = bodyIndex;
        if(encoding != 0) {
            /* Decode the body as a ByteString */
            ret = ByteString_decodeJson(ctx, &dst->content.encoded.body, NULL);
        } else {
            /* Use the JSON encoding directly */
            ret = tokenToByteString(ctx, &dst->content.encoded.body);
        }
        ctx->index = beginIndex;
        skipObject(ctx);
        return ret;
    }

    /* No need to keep the TypeId */
    UA_NodeId_clear(&typeId);

    /* Disallow directly nested ExtensionObjects */
    if(type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Allocate memory for the decoded data */
    dst->content.decoded.data = UA_new(type);
    if(!dst->content.decoded.data)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    dst->content.decoded.type = type;
    dst->encoding = UA_EXTENSIONOBJECT_DECODED;

    /* Get the body field index */
    size_t bodyIndex = ctx->index;
    ret = lookAheadForKey(ctx, UA_JSONKEY_BODY, &bodyIndex); /* Can fail */
    if(ret == UA_STATUSCODE_GOOD) {
        ctx->index = bodyIndex;
        ret = decodeJsonJumpTable[type->typeKind](ctx, dst->content.decoded.data, type);
        ctx->index = beginIndex;
        skipObject(ctx);
        return ret;
    }

    return decodeJsonJumpTable[type->typeKind](ctx, dst->content.decoded.data, type);
}

static status
Variant_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void *p, const UA_DataType *type) {
    (void) type;
    UA_Variant *dst = (UA_Variant*)p;

    /* ExtensionObject with null body */
    if(currentTokenType(ctx) == CJ5_TOKEN_NULL) {
        dst->data = UA_ExtensionObject_new();
        dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
        ctx->index++;
        return UA_STATUSCODE_GOOD;
    }

    /* Decode the ExtensionObject */
    UA_ExtensionObject eo;
    UA_ExtensionObject_init(&eo);
    UA_StatusCode ret = ExtensionObject_decodeJson(ctx, &eo, NULL);
    if(ret != UA_STATUSCODE_GOOD) {
        UA_ExtensionObject_clear(&eo); /* We don't have the global cleanup */
        return ret;
    }

    /* The content is still encoded, cannot unwrap */
    if(eo.encoding != UA_EXTENSIONOBJECT_DECODED)
        goto use_eo;

    /* The content is a builtin type that could have been directly encoded in
     * the Variant, there was no need to wrap in an ExtensionObject. But this
     * means for us, that somebody made an extra effort to explicitly get an
     * ExtensionObject. So we keep it. As an added advantage we will generate
     * the same JSON again when encoding again. */
    if(eo.content.decoded.type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO)
        goto use_eo;

    /* Unwrap the ExtensionObject */
    dst->data = eo.content.decoded.data;
    dst->type = eo.content.decoded.type;
    return UA_STATUSCODE_GOOD;

 use_eo:
    /* Don't unwrap */
    dst->data = UA_new(&UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
    if(!dst->data) {
        UA_ExtensionObject_clear(&eo);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
    *(UA_ExtensionObject*)dst->data = eo;
    return UA_STATUSCODE_GOOD;
}

status
DiagnosticInfoInner_decodeJson(ParseCtx* ctx, void* dst, const UA_DataType* type);

DECODE_JSON(DiagnosticInfo) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DiagnosticInfo */
    CHECK_OBJECT;

    DecodeEntry entries[7] = {
        {UA_JSONKEY_SYMBOLICID, &dst->symbolicId, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_NAMESPACEURI, &dst->namespaceUri, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_LOCALIZEDTEXT, &dst->localizedText, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_LOCALE, &dst->locale, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_ADDITIONALINFO, &dst->additionalInfo, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_INNERSTATUSCODE, &dst->innerStatusCode, NULL, false, &UA_TYPES[UA_TYPES_STATUSCODE]},
        {UA_JSONKEY_INNERDIAGNOSTICINFO, &dst->innerDiagnosticInfo, DiagnosticInfoInner_decodeJson, false, NULL}
    };
    status ret = decodeFields(ctx, entries, 7);

    dst->hasSymbolicId = entries[0].found;
    dst->hasNamespaceUri = entries[1].found;
    dst->hasLocalizedText = entries[2].found;
    dst->hasLocale = entries[3].found;
    dst->hasAdditionalInfo = entries[4].found;
    dst->hasInnerStatusCode = entries[5].found;
    dst->hasInnerDiagnosticInfo = entries[6].found;
    return ret;
}

status
DiagnosticInfoInner_decodeJson(ParseCtx* ctx, void* dst, const UA_DataType* type) {
    UA_DiagnosticInfo *inner = (UA_DiagnosticInfo*)
        UA_calloc(1, sizeof(UA_DiagnosticInfo));
    if(!inner)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_DiagnosticInfo **dst2 = (UA_DiagnosticInfo**)dst;
    *dst2 = inner;  /* Copy new Pointer do dest */
    return DiagnosticInfo_decodeJson(ctx, inner, type);
}

status
decodeFields(ParseCtx *ctx, DecodeEntry *entries, size_t entryCount) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NULL_SKIP; /* null is treated like an empty object */

    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Keys and values are counted separately */
    CHECK_OBJECT;
    UA_assert(ctx->tokens[ctx->index].size % 2 == 0);
    size_t keyCount = (size_t)(ctx->tokens[ctx->index].size) / 2;

    ctx->index++; /* Go to first key - or jump after the empty object */
    ctx->depth++;

    status ret = UA_STATUSCODE_GOOD;
    for(size_t key = 0; key < keyCount; key++) {
        /* Key must be a string */
        UA_assert(ctx->index < ctx->tokensSize);
        UA_assert(currentTokenType(ctx) == CJ5_TOKEN_STRING);

        /* Search for the decoding entry matching the key. Start at the key
         * index to speed-up the case where they key-order is the same as the
         * entry-order. */
        DecodeEntry *entry = NULL;
        for(size_t i = key; i < key + entryCount; i++) {
            size_t ii = i;
            while(ii >= entryCount)
                ii -= entryCount;

            /* Compare the key */
            if(jsoneq(ctx->json5, &ctx->tokens[ctx->index],
                      entries[ii].fieldName) != 0)
                continue;

            /* Key was already used -> duplicate, abort */
            if(entries[ii].found) {
                ctx->depth--;
                return UA_STATUSCODE_BADDECODINGERROR;
            }

            /* Found the key */
            entries[ii].found = true;
            entry = &entries[ii];
            break;
        }

        /* The key is unknown */
        if(!entry) {
            ret = UA_STATUSCODE_BADDECODINGERROR;
            break;
        }

        /* Go from key to value */
        ctx->index++;
        UA_assert(ctx->index < ctx->tokensSize);

        /* An entry that was expected but shall not be decoded.
         * Jump over the value. */
        if(!entry->function && !entry->type) {
            skipObject(ctx);
            continue;
        }

        /* A null-value, skip the decoding (the value is already initialized) */
        if(currentTokenType(ctx) == CJ5_TOKEN_NULL && !entry->function) {
            ctx->index++; /* skip null value */
            continue;
        }

        /* Decode. This also moves to the next key or right after the object for
         * the last value. */
        decodeJsonSignature decodeFunc = (entry->function) ?
            entry->function : decodeJsonJumpTable[entry->type->typeKind];
        ret = decodeFunc(ctx, entry->fieldPointer, entry->type);
        if(ret != UA_STATUSCODE_GOOD)
            break;
    }

    ctx->depth--;
    return ret;
}

static status
Array_decodeJson(ParseCtx *ctx, void **dst, const UA_DataType *type) {
    /* Save the length of the array */
    size_t *size_ptr = (size_t*) dst - 1;

    if(currentTokenType(ctx) != CJ5_TOKEN_ARRAY)
        return UA_STATUSCODE_BADDECODINGERROR;

    size_t length = (size_t)ctx->tokens[ctx->index].size;

    ctx->index++; /* Go to first array member or to the first element after
                   * the array (if empty) */

    /* Return early for empty arrays */
    if(length == 0) {
        *size_ptr = length;
        *dst = UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }

    /* Allocate memory */
    *dst = UA_calloc(length, type->memSize);
    if(*dst == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode array members */
    uintptr_t ptr = (uintptr_t)*dst;
    for(size_t i = 0; i < length; ++i) {
        if(ctx->tokens[ctx->index].type != CJ5_TOKEN_NULL) {
            status ret = decodeJsonJumpTable[type->typeKind](ctx, (void*)ptr, type);
            if(ret != UA_STATUSCODE_GOOD) {
                UA_Array_delete(*dst, i+1, type);
                *dst = NULL;
                return ret;
            }
        } else {
            ctx->index++;
        }
        ptr += type->memSize;
    }

    *size_ptr = length; /* All good, set the size */
    return UA_STATUSCODE_GOOD;
}

static status
decodeJsonStructure(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    /* Check the recursion limit */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    status ret = UA_STATUSCODE_GOOD;
    u8 membersSize = type->membersSize;
    UA_STACKARRAY(DecodeEntry, entries, membersSize);
    for(size_t i = 0; i < membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        entries[i].type = mt;
        entries[i].fieldName = m->memberName;
        entries[i].found = false;
        if(!m->isArray) {
            ptr += m->padding;
            entries[i].fieldPointer = (void*)ptr;
            entries[i].function = NULL;
            ptr += mt->memSize;
        } else {
            ptr += m->padding;
            ptr += sizeof(size_t);
            entries[i].fieldPointer = (void*)ptr;
            entries[i].function = (decodeJsonSignature)Array_decodeJson;
            ptr += sizeof(void*);
        }
    }

    ret = decodeFields(ctx, entries, membersSize);

    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth--;
    return ret;
}

static status
decodeJsonNotImplemented(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    (void)dst, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const decodeJsonSignature decodeJsonJumpTable[UA_DATATYPEKINDS] = {
    (decodeJsonSignature)Boolean_decodeJson,
    (decodeJsonSignature)SByte_decodeJson, /* SByte */
    (decodeJsonSignature)Byte_decodeJson,
    (decodeJsonSignature)Int16_decodeJson, /* Int16 */
    (decodeJsonSignature)UInt16_decodeJson,
    (decodeJsonSignature)Int32_decodeJson, /* Int32 */
    (decodeJsonSignature)UInt32_decodeJson,
    (decodeJsonSignature)Int64_decodeJson, /* Int64 */
    (decodeJsonSignature)UInt64_decodeJson,
    (decodeJsonSignature)Float_decodeJson,
    (decodeJsonSignature)Double_decodeJson,
    (decodeJsonSignature)String_decodeJson,
    (decodeJsonSignature)DateTime_decodeJson, /* DateTime */
    (decodeJsonSignature)Guid_decodeJson,
    (decodeJsonSignature)ByteString_decodeJson, /* ByteString */
    (decodeJsonSignature)String_decodeJson, /* XmlElement */
    (decodeJsonSignature)NodeId_decodeJson,
    (decodeJsonSignature)ExpandedNodeId_decodeJson,
    (decodeJsonSignature)StatusCode_decodeJson, /* StatusCode */
    (decodeJsonSignature)QualifiedName_decodeJson, /* QualifiedName */
    (decodeJsonSignature)LocalizedText_decodeJson,
    (decodeJsonSignature)ExtensionObject_decodeJson,
    (decodeJsonSignature)DataValue_decodeJson,
    (decodeJsonSignature)Variant_decodeJson,
    (decodeJsonSignature)DiagnosticInfo_decodeJson,
    (decodeJsonSignature)decodeJsonNotImplemented, /* Decimal */
    (decodeJsonSignature)Int32_decodeJson, /* Enum */
    (decodeJsonSignature)decodeJsonStructure,
    (decodeJsonSignature)decodeJsonNotImplemented, /* Structure with optional fields */
    (decodeJsonSignature)decodeJsonNotImplemented, /* Union */
    (decodeJsonSignature)decodeJsonNotImplemented /* BitfieldCluster */
};

status
tokenize(ParseCtx *ctx, const UA_ByteString *src, size_t tokensSize,
         size_t *decodedLength) {
    /* Tokenize */
    cj5_options options;
    options.stop_early = (decodedLength != NULL);
    cj5_result r = cj5_parse((char*)src->data, (unsigned int)src->length,
                             ctx->tokens, (unsigned int)tokensSize, &options);

    /* Handle overflow error by allocating the number of tokens the parser would
     * have needed */
    if(r.error == CJ5_ERROR_OVERFLOW &&
       tokensSize != r.num_tokens) {
        ctx->tokens = (cj5_token*)
            UA_malloc(sizeof(cj5_token) * r.num_tokens);
        if(!ctx->tokens)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        return tokenize(ctx, src, r.num_tokens, decodedLength);
    }

    /* Cannot recover from other errors */
    if(r.error != CJ5_ERROR_NONE)
        return UA_STATUSCODE_BADDECODINGERROR;

    if(decodedLength)
        *decodedLength = ctx->tokens[0].end + 1;

    /* Set up the context */
    ctx->json5 = (char*)src->data;
    ctx->depth = 0;
    ctx->tokensSize = r.num_tokens;
    ctx->index = 0;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type,
              const UA_DecodeJsonOptions *options) {
    if(!dst || !src || !type)
        return UA_STATUSCODE_BADARGUMENTSMISSING;

    /* Set up the context */
    cj5_token tokens[UA_JSON_MAXTOKENCOUNT];
    ParseCtx ctx;
    memset(&ctx, 0, sizeof(ParseCtx));
    ctx.tokens = tokens;

    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.customTypes = options->customTypes;
    }

    /* Decode */
    status ret = tokenize(&ctx, src, UA_JSON_MAXTOKENCOUNT,
                          options ? options->decodedLength : NULL);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;

    memset(dst, 0, type->memSize); /* Initialize the value */
    ret = decodeJsonJumpTable[type->typeKind](&ctx, dst, type);

    /* Sanity check if all tokens were processed */
    if(ctx.index != ctx.tokensSize &&
       ctx.index != ctx.tokensSize - 1)
        ret = UA_STATUSCODE_BADDECODINGERROR;

 cleanup:

    /* Free token array on the heap */
    if(ctx.tokens != tokens)
        UA_free((void*)(uintptr_t)ctx.tokens);

    if(ret != UA_STATUSCODE_GOOD)
        UA_clear(dst, type);
    return ret;
}

#endif /* defined(UA_ENABLE_JSON_ENCODING) && !defined(UA_ENABLE_JSON_ENCODING_LEGACY) */

/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage_json.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Lukas Meling)
 */



/* Json keys for dsm */
static const char * UA_DECODEKEY_MESSAGES = "Messages";
static const char * UA_DECODEKEY_MESSAGETYPE = "MessageType";
static const char * UA_DECODEKEY_MESSAGEID = "MessageId";
static const char * UA_DECODEKEY_PUBLISHERID = "PublisherId";
static const char * UA_DECODEKEY_DATASETCLASSID = "DataSetClassId";

/* Json keys for dsm */
static const char * UA_DECODEKEY_DATASETWRITERID = "DataSetWriterId";
static const char * UA_DECODEKEY_SEQUENCENUMBER = "SequenceNumber";
static const char * UA_DECODEKEY_METADATAVERSION = "MetaDataVersion";
static const char * UA_DECODEKEY_TIMESTAMP = "Timestamp";
static const char * UA_DECODEKEY_DSM_STATUS = "Status";
static const char * UA_DECODEKEY_PAYLOAD = "Payload";

/* -- json encoding/decoding -- */
static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, const UA_String *in) {
    UA_STACKARRAY(char, out, in->length + 1);
    if(in->length)
        memcpy(out, in->data, in->length);
    out[in->length] = 0;
    return writeJsonKey(ctx, out);
}

static UA_StatusCode
UA_DataSetMessage_encodeJson_internal(CtxJson *ctx,
                                      const UA_DataSetMessage_EncodingMetaData *emd,
                                      const UA_DataSetMessage *src) {
    status rv = writeJsonObjStart(ctx);

    /* DataSetWriterId */
    rv |= writeJsonObjElm(ctx, UA_DECODEKEY_DATASETWRITERID,
                          &emd->dataSetWriterId, &UA_TYPES[UA_TYPES_UINT16]);
    if(rv != UA_STATUSCODE_GOOD)
        return rv;

    /* TODO: Encode DataSetWriterName */

    /* TODO: Encode PublisherId (omitted if in the NetworkMessage header) */

    /* TODO: Encode WriterGroupName (omitted if in the NetworkMessage header) */

    /* DataSetMessageSequenceNr */
    if(src->header.dataSetMessageSequenceNrEnabled) {
        rv |= writeJsonObjElm(ctx, UA_DECODEKEY_SEQUENCENUMBER,
                              &src->header.dataSetMessageSequenceNr,
                              &UA_TYPES[UA_TYPES_UINT16]);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
    }

    /* MetaDataVersion */
    if(src->header.configVersionMajorVersionEnabled ||
       src->header.configVersionMinorVersionEnabled) {
        UA_ConfigurationVersionDataType cvd;
        cvd.majorVersion = src->header.configVersionMajorVersion;
        cvd.minorVersion = src->header.configVersionMinorVersion;
        rv |= writeJsonObjElm(ctx, UA_DECODEKEY_METADATAVERSION, &cvd,
                              &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
    }

    /* TODO: MinorVersion (omitted if the MetaDataVersion is sent) */

    /* Timestamp */
    if(src->header.timestampEnabled) {
        rv |= writeJsonObjElm(ctx, UA_DECODEKEY_TIMESTAMP, &src->header.timestamp,
                              &UA_TYPES[UA_TYPES_DATETIME]);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
    }

    /* Status */
    if(src->header.statusEnabled) {
        rv |= writeJsonObjElm(ctx, UA_DECODEKEY_DSM_STATUS,
                              &src->header.status, &UA_TYPES[UA_TYPES_UINT16]);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
    }

    /* MessageType */
    if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
        UA_String s = UA_STRING("ua-keyframe");
        rv |= writeJsonObjElm(ctx, UA_DECODEKEY_MESSAGETYPE,
                              &s, &UA_TYPES[UA_TYPES_STRING]);
    } else {
        /* TODO: Support other message types */
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    rv |= writeJsonKey(ctx, UA_DECODEKEY_PAYLOAD);
    rv |= writeJsonObjStart(ctx);

    if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
        /* Variant */
        for(UA_UInt16 i = 0; i < src->fieldCount; i++) {
            const UA_FieldMetaData *fmd = getFieldMetaData(emd, i);
            if(fmd)
                rv |= writeJsonKey_UA_String(ctx, &fmd->name);
            else
                rv |= writeJsonKey(ctx, "");
            rv |= encodeJsonJumpTable[UA_DATATYPEKIND_VARIANT]
                (ctx, &src->data.keyFrameFields[i].value, NULL);
            if(rv != UA_STATUSCODE_GOOD)
                return rv;
        }
    } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
        /* DataValue */
        for(UA_UInt16 i = 0; i < src->fieldCount; i++) {
            const UA_FieldMetaData *fmd = getFieldMetaData(emd, i);
            if(fmd)
                rv |= writeJsonKey_UA_String(ctx, &fmd->name);
            else
                rv |= writeJsonKey(ctx, "");
            rv |= encodeJsonJumpTable[UA_DATATYPEKIND_DATAVALUE]
                (ctx, &src->data.keyFrameFields[i], NULL);
            if(rv != UA_STATUSCODE_GOOD)
                return rv;
        }
    } else {
        /* RawData */
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }
    rv |= writeJsonObjEnd(ctx); /* Payload */
    rv |= writeJsonObjEnd(ctx); /* DataSetMessage */
    return rv;
}

UA_StatusCode
UA_NetworkMessage_encodeJsonInternal(PubSubEncodeJsonCtx *ctx,
                                     const UA_NetworkMessage *src) {
    /* currently only ua-data is supported, no discovery message implemented */
    if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    status rv = writeJsonObjStart(&ctx->ctx);

    /* Table 91 – JSON NetworkMessage Definition
     * MessageId | String | A globally unique identifier for the message.
     * This value is mandatory. But we don't check uniqueness in the
     * encoding layer. */
    rv |= writeJsonObjElm(&ctx->ctx, UA_DECODEKEY_MESSAGEID,
                          &src->messageId, &UA_TYPES[UA_TYPES_STRING]);

    /* MessageType */
    UA_String s = UA_STRING("ua-data");
    rv |= writeJsonObjElm(&ctx->ctx, UA_DECODEKEY_MESSAGETYPE,
                          &s, &UA_TYPES[UA_TYPES_STRING]);

    /* PublisherId, always encode as a JSON string */
    if(src->publisherIdEnabled) {
        UA_Byte buf[512];
        UA_ByteString bs = {512, buf};
        UA_Variant v;
        UA_PublisherId_toVariant(&src->publisherId, &v);
        rv |= UA_encodeJson(v.data, v.type, &bs, NULL);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
        rv |= writeJsonKey(&ctx->ctx, UA_DECODEKEY_PUBLISHERID);
        rv |= encodeJsonJumpTable[UA_DATATYPEKIND_STRING](&ctx->ctx, &bs, NULL);
    }
    if(rv != UA_STATUSCODE_GOOD)
        return rv;

    /* TODO: Encode WriterGroupName */

    /* DataSetClassId */
    if(src->dataSetClassIdEnabled) {
        rv |= writeJsonObjElm(&ctx->ctx, UA_DECODEKEY_DATASETCLASSID,
                              &src->dataSetClassId, &UA_TYPES[UA_TYPES_GUID]);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
    }

    /* Payload: DataSetMessages */
    size_t count = src->messageCount;
    if(count > 0) {
        rv |= writeJsonKey(&ctx->ctx, UA_DECODEKEY_MESSAGES);
        rv |= writeJsonArrStart(&ctx->ctx); /* start array */
        const UA_DataSetMessage *dsm = src->payload.dataSetMessages;
        for(size_t i = 0; i < count; i++) {
            const UA_DataSetMessage_EncodingMetaData *emd =
                findEncodingMetaData(&ctx->eo, src->dataSetWriterIds[i]);
            rv |= writeJsonBeforeElement(&ctx->ctx, true);
            rv |= UA_DataSetMessage_encodeJson_internal(&ctx->ctx, emd, &dsm[i]);
            if(rv != UA_STATUSCODE_GOOD)
                return rv;
            /* comma is needed if more dsm are present */
            ctx->ctx.commaNeeded[ctx->ctx.depth] = true;
        }

        rv |= writeJsonArrEnd(&ctx->ctx, NULL); /* end array */
    }

    rv |= writeJsonObjEnd(&ctx->ctx);
    return rv;
}

UA_StatusCode
UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src,
                             UA_ByteString *outBuf,
                             const UA_NetworkMessage_EncodingOptions *eo,
                             const UA_EncodeJsonOptions *jo) {
    UA_Boolean alloced = (outBuf->length == 0);
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(alloced) {
        size_t length = UA_NetworkMessage_calcSizeJson(src, eo, jo);
        if(length == 0)
            return UA_STATUSCODE_BADENCODINGERROR;
        ret = UA_ByteString_allocBuffer(outBuf, length);
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
    }

    /* Set up the context */
    PubSubEncodeJsonCtx ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.ctx.pos = outBuf->data;
    ctx.ctx.end = outBuf->data + outBuf->length;
    ctx.ctx.calcOnly = false;
    if(eo)
        ctx.eo = *eo;
    if(jo) {
        ctx.ctx.useReversible = jo->useReversible;
        ctx.ctx.namespaceMapping = jo->namespaceMapping;
        ctx.ctx.serverUrisSize = jo->serverUrisSize;
        ctx.ctx.serverUris = jo->serverUris;
        ctx.ctx.prettyPrint = jo->prettyPrint;
        ctx.ctx.unquotedKeys = jo->unquotedKeys;
        ctx.ctx.stringNodeIds = jo->stringNodeIds;
    }

    ret = UA_NetworkMessage_encodeJsonInternal(&ctx, src);

    /* In case the buffer was supplied externally and is longer than the encoded
     * string */
    if(UA_LIKELY(ret == UA_STATUSCODE_GOOD))
        outBuf->length = (size_t)((uintptr_t)ctx.ctx.pos - (uintptr_t)outBuf->data);

    if(alloced && ret != UA_STATUSCODE_GOOD)
        UA_String_clear(outBuf);
    return ret;
}

size_t
UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src,
                               const UA_NetworkMessage_EncodingOptions *eo,
                               const UA_EncodeJsonOptions *jo) {
    /* Set up the context */
    PubSubEncodeJsonCtx ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
    ctx.ctx.calcOnly = true;
    if(eo)
        ctx.eo = *eo;
    if(jo) {
        ctx.ctx.useReversible = jo->useReversible;
        ctx.ctx.namespaceMapping = jo->namespaceMapping;
        ctx.ctx.serverUrisSize = jo->serverUrisSize;
        ctx.ctx.serverUris = jo->serverUris;
        ctx.ctx.prettyPrint = jo->prettyPrint;
        ctx.ctx.unquotedKeys = jo->unquotedKeys;
        ctx.ctx.stringNodeIds = jo->stringNodeIds;
    }

    status ret = UA_NetworkMessage_encodeJsonInternal(&ctx, src);
    if(ret != UA_STATUSCODE_GOOD)
        return 0;

    return (size_t)ctx.ctx.pos;
}

/* decode json */
static status
MetaDataVersion_decodeJsonInternal(ParseCtx *ctx, void* cvd, const UA_DataType *_) {
    return decodeJsonJumpTable[UA_DATATYPEKIND_STRUCTURE]
        (ctx, cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
}

static size_t
decodingFieldIndex(const UA_DataSetMessage_EncodingMetaData *emd,
                   UA_String name, size_t origIndex) {
    if(!emd)
        return origIndex;
    for(size_t i = 0; i < emd->fieldsSize; i++) {
        if(UA_String_equal(&name, &emd->fields[i].name))
            return i;
    }
    return origIndex;
}

struct PayloadData {
    UA_NetworkMessage *nm;
    size_t dsmIndex;
};

static status
DataSetPayload_decodeJsonInternal(PubSubDecodeJsonCtx *ctx, void *data, const UA_DataType *_) {
    struct PayloadData *pd = (struct PayloadData*)data;
    UA_NetworkMessage *nm = pd->nm;
    UA_DataSetMessage *dsm = &nm->payload.dataSetMessages[pd->dsmIndex];

    dsm->header.dataSetMessageValid = true;

    if(currentTokenType(&ctx->ctx) == CJ5_TOKEN_NULL) {
        ctx->ctx.index++;
        return UA_STATUSCODE_GOOD;
    }

    if(currentTokenType(&ctx->ctx) != CJ5_TOKEN_OBJECT)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* The number of key-value pairs */
    UA_assert(ctx->ctx.tokens[ctx->ctx.index].size % 2 == 0);
    size_t length = (size_t)(ctx->ctx.tokens[ctx->ctx.index].size) / 2;

    if(length > UA_UINT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;

    dsm->data.keyFrameFields = (UA_DataValue *)
        UA_Array_new(length, &UA_TYPES[UA_TYPES_DATAVALUE]);
    if(!dsm->data.keyFrameFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    dsm->fieldCount = (UA_UInt16)length;

    dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;

    const UA_DataSetMessage_EncodingMetaData *emd =
            findEncodingMetaData(&ctx->eo, nm->dataSetWriterIds[pd->dsmIndex]);

    /* Iterate over the key/value pairs in the object. Keys are stored in fieldnames. */
    ctx->ctx.index++; /* Go to the first key */
    status ret = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < length; ++i) {
        UA_assert(currentTokenType(&ctx->ctx) == CJ5_TOKEN_STRING);
        UA_String fieldName = UA_STRING_NULL;
        ret = decodeJsonJumpTable[UA_DATATYPEKIND_STRING](&ctx->ctx, &fieldName, NULL);
        UA_CHECK_STATUS(ret, return ret);

        size_t index = decodingFieldIndex(emd, fieldName, i);
        if(index >= length) {
            UA_String_clear(&fieldName);
            return UA_STATUSCODE_BADDECODINGERROR;
        }
        UA_DataValue_clear(&dsm->data.keyFrameFields[index]);
        UA_String_clear(&fieldName);
        ret = decodeJsonJumpTable[UA_DATATYPEKIND_DATAVALUE]
            (&ctx->ctx, &dsm->data.keyFrameFields[index], NULL);
        UA_CHECK_STATUS(ret, return ret);
    }

    return ret;
}

static status
DatasetMessage_Payload_decodeJsonInternal(PubSubDecodeJsonCtx *ctx, UA_NetworkMessage *nm,
                                          size_t dsmIndex) {
    UA_DataSetMessage *dsm = &nm->payload.dataSetMessages[dsmIndex];
    UA_ConfigurationVersionDataType cvd;
    struct PayloadData pd;
    pd.nm = nm;
    pd.dsmIndex = dsmIndex;

    DecodeEntry entries[7] = {
        {UA_DECODEKEY_DATASETWRITERID, &nm->dataSetWriterIds[dsmIndex], NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
        {UA_DECODEKEY_SEQUENCENUMBER, &dsm->header.dataSetMessageSequenceNr, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
        {UA_DECODEKEY_METADATAVERSION, &cvd, &MetaDataVersion_decodeJsonInternal, false, NULL},
        {UA_DECODEKEY_TIMESTAMP, &dsm->header.timestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
        {UA_DECODEKEY_DSM_STATUS, &dsm->header.status, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
        {UA_DECODEKEY_MESSAGETYPE, NULL, NULL, false, NULL},
        {UA_DECODEKEY_PAYLOAD, &pd, (decodeJsonSignature)DataSetPayload_decodeJsonInternal, false, NULL}
    };
    status ret = decodeFields(&ctx->ctx, entries, 7);

    /* Error or no DatasetWriterId found or no payload found */
    if(ret != UA_STATUSCODE_GOOD || !entries[0].found || !entries[6].found)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* TODO: Check FieldEncoding1 and FieldEncoding2 to determine the field encoding */
    dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
    dsm->header.dataSetMessageSequenceNrEnabled = entries[1].found;
    dsm->header.configVersionMajorVersion = cvd.majorVersion;
    dsm->header.configVersionMinorVersion = cvd.minorVersion;
    dsm->header.configVersionMajorVersionEnabled = entries[2].found;
    dsm->header.configVersionMinorVersionEnabled = entries[2].found;
    dsm->header.timestampEnabled = entries[3].found;
    dsm->header.statusEnabled = entries[4].found;

    dsm->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
    dsm->header.picoSecondsIncluded = false;
    dsm->header.dataSetMessageValid = true;
    dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
    return UA_STATUSCODE_GOOD;
}

static status
DatasetMessage_Array_decodeJsonInternal(PubSubDecodeJsonCtx *ctx, void *UA_RESTRICT dst,
                                        const UA_DataType *_) {
    /* Array or object */
    size_t length = 1;
    if(currentTokenType(&ctx->ctx) == CJ5_TOKEN_ARRAY) {
        length = (size_t)ctx->ctx.tokens[ctx->ctx.index].size;

        /* Go to the first array member */
        ctx->ctx.index++;

        /* Return early for empty arrays */
        if(length == 0)
            return UA_STATUSCODE_GOOD;
    } else if(currentTokenType(&ctx->ctx) != CJ5_TOKEN_OBJECT) {
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Decode array members */
    UA_NetworkMessage *nm = (UA_NetworkMessage*)dst;
    for(size_t i = 0; i < length; ++i) {
        status ret = DatasetMessage_Payload_decodeJsonInternal(ctx, nm, i);
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
    }

    return UA_STATUSCODE_GOOD;
}

static status
decodePublisherIdJsonInternal(ParseCtx *ctx, void *UA_RESTRICT dst,
                              const UA_DataType *type) {
    UA_PublisherId *p = (UA_PublisherId*)dst;
    if(currentTokenType(ctx) == CJ5_TOKEN_NUMBER) {
        /* Store in biggest possible integer. The problem is that with a UInt64
         * is that a string is expected for it in JSON. Therefore, the maximum
         * value is set to UInt32. */
        p->idType = UA_PUBLISHERIDTYPE_UINT32;
        return decodeJsonJumpTable[UA_DATATYPEKIND_UINT32](ctx, &p->id.uint32, NULL);
    } else if(currentTokenType(ctx) == CJ5_TOKEN_STRING) {
        p->idType = UA_PUBLISHERIDTYPE_STRING;
        return decodeJsonJumpTable[UA_DATATYPEKIND_STRING](ctx, &p->id.string, NULL);
    }
    return UA_STATUSCODE_BADDECODINGERROR;
}

static status
NetworkMessage_decodeJsonInternal(PubSubDecodeJsonCtx *ctx,
                                  UA_NetworkMessage *dst) {
    memset(dst, 0, sizeof(UA_NetworkMessage));
    dst->chunkMessage = false;
    dst->groupHeaderEnabled = false;
    dst->payloadHeaderEnabled = false;
    dst->picosecondsEnabled = false;
    dst->promotedFieldsEnabled = false;

    /* The NetworkMessage must be a JSON object */
    if(currentTokenType(&ctx->ctx) != CJ5_TOKEN_OBJECT)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Is Messages an Array? How big? */
    size_t searchResultMessages = 0;
    status found = lookAheadForKey(&ctx->ctx, UA_DECODEKEY_MESSAGES, &searchResultMessages);
    if(found != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    const cj5_token *bodyToken = &ctx->ctx.tokens[searchResultMessages];
    size_t messageCount = 1;
    if(bodyToken->type == CJ5_TOKEN_ARRAY)
        messageCount = (size_t)bodyToken->size;

    /* Too many DataSetMessages */
    if(messageCount > UA_NETWORKMESSAGE_MAXMESSAGECOUNT)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* MessageType */
    UA_Boolean isUaData = true;
    size_t searchResultMessageType = 0;
    found = lookAheadForKey(&ctx->ctx, UA_DECODEKEY_MESSAGETYPE, &searchResultMessageType);
    if(found != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;
    size_t size = getTokenLength(&ctx->ctx.tokens[searchResultMessageType]);
    const char* msgType = &ctx->ctx.json5[ctx->ctx.tokens[searchResultMessageType].start];
    if(size == 7) { //ua-data
        if(strncmp(msgType, "ua-data", size) != 0)
            return UA_STATUSCODE_BADDECODINGERROR;
        isUaData = true;
    } else if(size == 11) { //ua-metadata
        if(strncmp(msgType, "ua-metadata", size) != 0)
            return UA_STATUSCODE_BADDECODINGERROR;
        isUaData = false;
    } else {
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    //TODO: MetaData
    if(!isUaData)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    dst->payload.dataSetMessages = (UA_DataSetMessage*)
        UA_calloc(messageCount, sizeof(UA_DataSetMessage));
    if(!dst->payload.dataSetMessages)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    dst->messageCount = (UA_Byte)messageCount;

    /* Network Message */
    UA_String messageType;
    DecodeEntry entries[5] = {
        {UA_DECODEKEY_MESSAGEID, &dst->messageId, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_DECODEKEY_MESSAGETYPE, &messageType, NULL, false, NULL},
        {UA_DECODEKEY_PUBLISHERID, &dst->publisherId, decodePublisherIdJsonInternal, false, NULL},
        {UA_DECODEKEY_DATASETCLASSID, &dst->dataSetClassId, NULL, false, &UA_TYPES[UA_TYPES_GUID]},
        {UA_DECODEKEY_MESSAGES, dst, (decodeJsonSignature)DatasetMessage_Array_decodeJsonInternal, false, NULL}
    };

    status ret = decodeFields(&ctx->ctx, entries, 5);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    dst->messageIdEnabled = entries[0].found;
    dst->publisherIdEnabled = entries[2].found;
    dst->dataSetClassIdEnabled = entries[3].found;
    dst->payloadHeaderEnabled = true;

    return ret;
}

UA_StatusCode
UA_NetworkMessage_decodeJson(const UA_ByteString *src,
                             UA_NetworkMessage *dst,
                             const UA_NetworkMessage_EncodingOptions *eo,
                             const UA_DecodeJsonOptions *jo) {
    /* Set up the context */
    cj5_token tokens[UA_JSON_MAXTOKENCOUNT];
    PubSubDecodeJsonCtx ctx;
    memset(&ctx, 0, sizeof(PubSubDecodeJsonCtx));
    ctx.ctx.tokens = tokens;
    if(eo)
        ctx.eo = *eo;
    if(jo) {
        ctx.ctx.namespaceMapping = jo->namespaceMapping;
        ctx.ctx.serverUrisSize = jo->serverUrisSize;
        ctx.ctx.serverUris = jo->serverUris;
        ctx.ctx.customTypes = jo->customTypes;
    }

    status ret = tokenize(&ctx.ctx, src, UA_JSON_MAXTOKENCOUNT, NULL);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;

    ret = NetworkMessage_decodeJsonInternal(&ctx, dst);
    if(ret != UA_STATUSCODE_GOOD)
        UA_NetworkMessage_clear(dst);

 cleanup:
    /* Free token array on the heap */
    if(ctx.ctx.tokens != tokens)
        UA_free((void*)(uintptr_t)ctx.ctx.tokens);
    return ret;
}

/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage_binary.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Andreas Ebner)
 */



#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

#define _DECODE_BINARY(VAR, TYPE)                                       \
    decodeBinaryJumpTable[UA_DATATYPEKIND_##TYPE](&ctx->ctx, VAR, NULL);
#define _ENCODE_BINARY(VAR, TYPE)                                       \
    encodeBinaryJumpTable[UA_DATATYPEKIND_##TYPE](&ctx->ctx, VAR, NULL);

#define NM_VERSION_MASK 15
#define NM_PUBLISHER_ID_ENABLED_MASK 16
#define NM_GROUP_HEADER_ENABLED_MASK 32
#define NM_PAYLOAD_HEADER_ENABLED_MASK 64
#define NM_EXTENDEDFLAGS1_ENABLED_MASK 128
#define NM_PUBLISHER_ID_MASK 7
#define NM_DATASET_CLASSID_ENABLED_MASK 8
#define NM_SECURITY_ENABLED_MASK 16
#define NM_TIMESTAMP_ENABLED_MASK 32
#define NM_PICOSECONDS_ENABLED_MASK 64
#define NM_EXTENDEDFLAGS2_ENABLED_MASK 128
#define NM_NETWORK_MSG_TYPE_MASK 28
#define NM_CHUNK_MESSAGE_MASK 1
#define NM_PROMOTEDFIELDS_ENABLED_MASK 2
#define GROUP_HEADER_WRITER_GROUPID_ENABLED 1
#define GROUP_HEADER_GROUP_VERSION_ENABLED 2
#define GROUP_HEADER_NM_NUMBER_ENABLED 4
#define GROUP_HEADER_SEQUENCE_NUMBER_ENABLED 8
#define SECURITY_HEADER_NM_SIGNED 1
#define SECURITY_HEADER_NM_ENCRYPTED 2
#define SECURITY_HEADER_SEC_FOOTER_ENABLED 4
#define SECURITY_HEADER_FORCE_KEY_RESET 8
#define DS_MESSAGEHEADER_DS_MSG_VALID 1
#define DS_MESSAGEHEADER_FIELD_ENCODING_MASK 6
#define DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK 8
#define DS_MESSAGEHEADER_STATUS_ENABLED_MASK 16
#define DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK 32
#define DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK 64
#define DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK 128
#define DS_MESSAGEHEADER_DS_MESSAGE_TYPE_MASK 15
#define DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK 16
#define DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK 32
#define NM_SHIFT_LEN 2
#define DS_MH_SHIFT_LEN 1

static UA_Boolean UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessage* src);
static UA_Boolean UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src);
static UA_Boolean UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src);

static UA_StatusCode
UA_NetworkMessageHeader_encodeBinary(PubSubEncodeCtx *ctx,
                                     const UA_NetworkMessage *src) {
    /* UADPVersion + UADP Flags */
    UA_Byte v = src->version;
    if(src->publisherIdEnabled)
        v |= NM_PUBLISHER_ID_ENABLED_MASK;

    if(src->groupHeaderEnabled)
        v |= NM_GROUP_HEADER_ENABLED_MASK;

    if(src->payloadHeaderEnabled)
        v |= NM_PAYLOAD_HEADER_ENABLED_MASK;

    if(UA_NetworkMessage_ExtendedFlags1Enabled(src))
        v |= NM_EXTENDEDFLAGS1_ENABLED_MASK;

    UA_StatusCode rv = _ENCODE_BINARY(&v, BYTE);
    UA_CHECK_STATUS(rv, return rv);
    /* ExtendedFlags1 */
    if(UA_NetworkMessage_ExtendedFlags1Enabled(src)) {
        v = (UA_Byte)src->publisherId.idType;

        if(src->dataSetClassIdEnabled)
            v |= NM_DATASET_CLASSID_ENABLED_MASK;

        if(src->securityEnabled)
            v |= NM_SECURITY_ENABLED_MASK;

        if(src->timestampEnabled)
            v |= NM_TIMESTAMP_ENABLED_MASK;

        if(src->picosecondsEnabled)
            v |= NM_PICOSECONDS_ENABLED_MASK;

        if(UA_NetworkMessage_ExtendedFlags2Enabled(src))
            v |= NM_EXTENDEDFLAGS2_ENABLED_MASK;

        rv = _ENCODE_BINARY(&v, BYTE);
        UA_CHECK_STATUS(rv, return rv);

        /* ExtendedFlags2 */
        if(UA_NetworkMessage_ExtendedFlags2Enabled(src)) {
            v = (UA_Byte)src->networkMessageType;
            /* Shift left 2 bit */
            v = (UA_Byte) (v << NM_SHIFT_LEN);

            if(src->chunkMessage)
                v |= NM_CHUNK_MESSAGE_MASK;

            if(src->promotedFieldsEnabled)
                v |= NM_PROMOTEDFIELDS_ENABLED_MASK;

            rv = _ENCODE_BINARY(&v, BYTE);
            UA_CHECK_STATUS(rv, return rv);
        }
    }

    /* PublisherId */
    if(src->publisherIdEnabled) {
        switch (src->publisherId.idType) {
        case UA_PUBLISHERIDTYPE_BYTE:
            rv = _ENCODE_BINARY(&src->publisherId.id.byte, BYTE); break;
        case UA_PUBLISHERIDTYPE_UINT16:
            rv = _ENCODE_BINARY(&src->publisherId.id.uint16, UINT16); break;
        case UA_PUBLISHERIDTYPE_UINT32:
            rv = _ENCODE_BINARY(&src->publisherId.id.uint32, UINT32); break;
        case UA_PUBLISHERIDTYPE_UINT64:
            rv = _ENCODE_BINARY(&src->publisherId.id.uint64, UINT64); break;
        case UA_PUBLISHERIDTYPE_STRING:
            rv = _ENCODE_BINARY(&src->publisherId.id.string, STRING); break;
        default:
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        UA_CHECK_STATUS(rv, return rv);
    }

    /* DataSetClassId */
    if(src->dataSetClassIdEnabled) {
        rv = _ENCODE_BINARY(&src->dataSetClassId, GUID);
        UA_CHECK_STATUS(rv, return rv);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_GroupHeader_encodeBinary(PubSubEncodeCtx *ctx, const UA_NetworkMessage* src) {
    UA_Byte v = 0;
    if(src->groupHeader.writerGroupIdEnabled)
        v |= GROUP_HEADER_WRITER_GROUPID_ENABLED;

    if(src->groupHeader.groupVersionEnabled)
        v |= GROUP_HEADER_GROUP_VERSION_ENABLED;

    if(src->groupHeader.networkMessageNumberEnabled)
        v |= GROUP_HEADER_NM_NUMBER_ENABLED;

    if(src->groupHeader.sequenceNumberEnabled)
        v |= GROUP_HEADER_SEQUENCE_NUMBER_ENABLED;

    UA_StatusCode rv = _ENCODE_BINARY(&v, BYTE);
    if(src->groupHeader.writerGroupIdEnabled)
        rv |= _ENCODE_BINARY(&src->groupHeader.writerGroupId, UINT16);

    if(src->groupHeader.groupVersionEnabled)
        rv |= _ENCODE_BINARY(&src->groupHeader.groupVersion, UINT32);

    if(src->groupHeader.networkMessageNumberEnabled)
        rv |= _ENCODE_BINARY(&src->groupHeader.networkMessageNumber, UINT16);

    if(src->groupHeader.sequenceNumberEnabled)
        rv |= _ENCODE_BINARY(&src->groupHeader.sequenceNumber, UINT16);

    return rv;
}

static UA_StatusCode
UA_PayloadHeader_encodeBinary(PubSubEncodeCtx *ctx, const UA_NetworkMessage* src) {
    if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    UA_Byte count = src->messageCount;
    UA_StatusCode rv = _ENCODE_BINARY(&count, BYTE);
    for(UA_Byte i = 0; i < src->messageCount; i++) {
        rv |= _ENCODE_BINARY(&src->dataSetWriterIds[i], UINT16);
    }
    return rv;
}

static UA_StatusCode
UA_ExtendedNetworkMessageHeader_encodeBinary(PubSubEncodeCtx *ctx,
                                             const UA_NetworkMessage* src) {
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    if(src->timestampEnabled)
        rv |= _ENCODE_BINARY(&src->timestamp, DATETIME);

    if(src->picosecondsEnabled)
        rv |= _ENCODE_BINARY(&src->picoseconds, UINT16);

    if(src->promotedFieldsEnabled) {
        /* Size (calculate & encode) */
        UA_UInt16 pfSize = 0;
        for(UA_UInt16 i = 0; i < src->promotedFieldsSize; i++)
            pfSize = (UA_UInt16)(pfSize + UA_Variant_calcSizeBinary(&src->promotedFields[i]));
        rv |= _ENCODE_BINARY(&pfSize, UINT16);

        for(UA_UInt16 i = 0; i < src->promotedFieldsSize; i++)
            rv |= _ENCODE_BINARY(&src->promotedFields[i], VARIANT);
    }

    return rv;
}

static UA_StatusCode
UA_SecurityHeader_encodeBinary(PubSubEncodeCtx *ctx,
                               const UA_NetworkMessage* src) {
    /* SecurityFlags */
    UA_Byte v = 0;
    if(src->securityHeader.networkMessageSigned)
        v |= SECURITY_HEADER_NM_SIGNED;

    if(src->securityHeader.networkMessageEncrypted)
        v |= SECURITY_HEADER_NM_ENCRYPTED;

    if(src->securityHeader.securityFooterEnabled)
        v |= SECURITY_HEADER_SEC_FOOTER_ENABLED;

    if(src->securityHeader.forceKeyReset)
        v |= SECURITY_HEADER_FORCE_KEY_RESET;

    UA_StatusCode rv = _ENCODE_BINARY(&v, BYTE);

    /* SecurityTokenId */
    rv |= _ENCODE_BINARY(&src->securityHeader.securityTokenId, UINT32);

    /* NonceLength */
    UA_Byte nonceLength = (UA_Byte)src->securityHeader.messageNonceSize;
    rv |= _ENCODE_BINARY(&nonceLength, BYTE);

    /* MessageNonce */
    for(size_t i = 0; i < src->securityHeader.messageNonceSize; i++) {
        rv |= _ENCODE_BINARY(&src->securityHeader.messageNonce[i], BYTE);
    }

    /* SecurityFooterSize */
    if(src->securityHeader.securityFooterEnabled) {
        rv |= _ENCODE_BINARY(&src->securityHeader.securityFooterSize, UINT16);
    }

    return rv;
}

UA_StatusCode
UA_NetworkMessage_encodeHeaders(PubSubEncodeCtx *ctx,
                                const UA_NetworkMessage* src) {
    /* Message Header */
    UA_StatusCode rv = UA_NetworkMessageHeader_encodeBinary(ctx, src);

    /* Group Header */
    if(src->groupHeaderEnabled)
        rv |= UA_GroupHeader_encodeBinary(ctx, src);

    /* Payload Header */
    if(src->payloadHeaderEnabled)
        rv |= UA_PayloadHeader_encodeBinary(ctx, src);

    /* Extended Network Message Header */
    rv |= UA_ExtendedNetworkMessageHeader_encodeBinary(ctx, src);

    /* SecurityHeader */
    if(src->securityEnabled)
        rv |= UA_SecurityHeader_encodeBinary(ctx, src);

    return rv;
}

const UA_DataSetMessage_EncodingMetaData *
findEncodingMetaData(const UA_NetworkMessage_EncodingOptions *eo,
                     UA_UInt16 dsWriterId) {
    if(!eo)
        return NULL;
    for(size_t i = 0; i < eo->metaDataSize; i++) {
        if(eo->metaData[i].dataSetWriterId == dsWriterId)
            return &eo->metaData[i];
    }
    return NULL;
}

const UA_FieldMetaData *
getFieldMetaData(const UA_DataSetMessage_EncodingMetaData *emd,
                 size_t index) {
    if(!emd)
        return NULL;
    if(index > emd->fieldsSize)
        return NULL;
    return &emd->fields[index];
}

UA_StatusCode
UA_NetworkMessage_encodePayload(PubSubEncodeCtx *ctx,
                                const UA_NetworkMessage* src) {
    /* Only DataSet support so far */
    if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    /* Encode the length of each DataSet */
    UA_Byte count = src->messageCount;
    UA_StatusCode rv;
    if(src->payloadHeaderEnabled && count > 1) {
        for(UA_Byte i = 0; i < count; i++) {
            UA_DataSetMessage *dsm = &src->payload.dataSetMessages[i];
            const UA_DataSetMessage_EncodingMetaData *emd =
                findEncodingMetaData(&ctx->eo, src->dataSetWriterIds[i]);
            UA_UInt16 sz = (UA_UInt16)UA_DataSetMessage_calcSizeBinary(ctx, emd, dsm, 0);
            rv = _ENCODE_BINARY(&sz, UINT16);
            UA_CHECK_STATUS(rv, return rv);
        }
    }

    /* Encode the DataSets  */
    for(UA_Byte i = 0; i < count; i++) {
        UA_DataSetMessage *dsm = &src->payload.dataSetMessages[i];
        const UA_DataSetMessage_EncodingMetaData *emd =
            findEncodingMetaData(&ctx->eo, src->dataSetWriterIds[i]);
        rv = UA_DataSetMessage_encodeBinary(ctx, emd, dsm);
        UA_CHECK_STATUS(rv, return rv);
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_NetworkMessage_encodeFooters(PubSubEncodeCtx *ctx,
                                const UA_NetworkMessage* src) {
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    if(src->securityEnabled &&
       src->securityHeader.securityFooterEnabled) {
        for(size_t i = 0; i < src->securityHeader.securityFooterSize; i++) {
            rv |= _ENCODE_BINARY(&src->securityFooter.data[i], BYTE);
        }
    }
    return rv;
}

UA_StatusCode
UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src,
                               UA_ByteString *outBuf,
                               const UA_NetworkMessage_EncodingOptions *eo) {
    /* Allocate the buffer */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_Boolean alloced = (outBuf->length == 0);
    if(alloced) {
        size_t length = UA_NetworkMessage_calcSizeBinary(src, eo);
        if(length == 0)
            return UA_STATUSCODE_BADENCODINGERROR;
        res = UA_ByteString_allocBuffer(outBuf, length);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Encode the NetworkMessage */
    PubSubEncodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubEncodeCtx));
    ctx.ctx.pos = outBuf->data;
    ctx.ctx.end = outBuf->data + outBuf->length;
    if(eo)
        ctx.eo = *eo;
    res = UA_NetworkMessage_encodeBinaryWithEncryptStart(&ctx, src, NULL);

    /* In case the buffer was supplied externally and is longer than the encoded
     * string */
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        outBuf->length = (size_t)((uintptr_t)ctx.ctx.pos - (uintptr_t)outBuf->data);

    if(alloced && res != UA_STATUSCODE_GOOD)
        UA_ByteString_clear(outBuf);
    return res;
}

UA_StatusCode
UA_NetworkMessage_encodeBinaryWithEncryptStart(PubSubEncodeCtx *ctx,
                                               const UA_NetworkMessage* src,
                                               UA_Byte **dataToEncryptStart) {
    UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(ctx, src);
    if(dataToEncryptStart)
        *dataToEncryptStart = ctx->ctx.pos;
    rv |= UA_NetworkMessage_encodePayload(ctx, src);
    rv |= UA_NetworkMessage_encodeFooters(ctx, src);
    return rv;
}

static UA_StatusCode
UA_NetworkMessageHeader_decodeBinary(PubSubDecodeCtx *ctx,
                                     UA_NetworkMessage *nm) {
    UA_Byte decoded;
    UA_StatusCode rv = _DECODE_BINARY(&decoded, BYTE);
    UA_CHECK_STATUS(rv, return rv);

    nm->version = decoded & NM_VERSION_MASK;

    if((decoded & NM_PUBLISHER_ID_ENABLED_MASK) != 0)
        nm->publisherIdEnabled = true;

    if((decoded & NM_GROUP_HEADER_ENABLED_MASK) != 0)
        nm->groupHeaderEnabled = true;

    if((decoded & NM_PAYLOAD_HEADER_ENABLED_MASK) != 0)
        nm->payloadHeaderEnabled = true;

    if((decoded & NM_EXTENDEDFLAGS1_ENABLED_MASK) != 0) {
        rv = _DECODE_BINARY(&decoded, BYTE);
        UA_CHECK_STATUS(rv, return rv);

        nm->publisherId.idType = (UA_PublisherIdType)(decoded & NM_PUBLISHER_ID_MASK);
        if((decoded & NM_DATASET_CLASSID_ENABLED_MASK) != 0)
            nm->dataSetClassIdEnabled = true;

        if((decoded & NM_SECURITY_ENABLED_MASK) != 0)
            nm->securityEnabled = true;

        if((decoded & NM_TIMESTAMP_ENABLED_MASK) != 0)
            nm->timestampEnabled = true;

        if((decoded & NM_PICOSECONDS_ENABLED_MASK) != 0)
            nm->picosecondsEnabled = true;

        if((decoded & NM_EXTENDEDFLAGS2_ENABLED_MASK) != 0) {
            rv = _DECODE_BINARY(&decoded, BYTE);
            UA_CHECK_STATUS(rv, return rv);

            if((decoded & NM_CHUNK_MESSAGE_MASK) != 0)
                nm->chunkMessage = true;

            if((decoded & NM_PROMOTEDFIELDS_ENABLED_MASK) != 0)
                nm->promotedFieldsEnabled = true;

            decoded = decoded & NM_NETWORK_MSG_TYPE_MASK;
            decoded = (UA_Byte) (decoded >> NM_SHIFT_LEN);
            nm->networkMessageType = (UA_NetworkMessageType)decoded;
        }
    }

    if(nm->publisherIdEnabled) {
        switch(nm->publisherId.idType) {
            case UA_PUBLISHERIDTYPE_BYTE:
                rv = _DECODE_BINARY(&nm->publisherId.id.byte, BYTE);
                break;
            case UA_PUBLISHERIDTYPE_UINT16:
                rv = _DECODE_BINARY(&nm->publisherId.id.uint16, UINT16);
                break;
            case UA_PUBLISHERIDTYPE_UINT32:
                rv = _DECODE_BINARY(&nm->publisherId.id.uint32, UINT32);
                break;
            case UA_PUBLISHERIDTYPE_UINT64:
                rv = _DECODE_BINARY(&nm->publisherId.id.uint64, UINT64);
                break;
            case UA_PUBLISHERIDTYPE_STRING:
                rv = _DECODE_BINARY(&nm->publisherId.id.string, STRING);
                break;
            default:
                rv = UA_STATUSCODE_BADINTERNALERROR;
                break;
        }
        UA_CHECK_STATUS(rv, return rv);
    }

    if(nm->dataSetClassIdEnabled) {
        rv = _DECODE_BINARY(&nm->dataSetClassId, GUID);
        UA_CHECK_STATUS(rv, return rv);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_GroupHeader_decodeBinary(PubSubDecodeCtx *ctx,
                            UA_NetworkMessage* nm) {
    UA_Byte decoded;
    UA_StatusCode rv = _DECODE_BINARY(&decoded, BYTE);
    UA_CHECK_STATUS(rv, return rv);

    if((decoded & GROUP_HEADER_WRITER_GROUPID_ENABLED) != 0) {
        nm->groupHeader.writerGroupIdEnabled = true;
        rv |= _DECODE_BINARY(&nm->groupHeader.writerGroupId, UINT16);
    }

    if((decoded & GROUP_HEADER_GROUP_VERSION_ENABLED) != 0) {
        nm->groupHeader.groupVersionEnabled = true;
        rv |= _DECODE_BINARY(&nm->groupHeader.groupVersion, UINT32);
    }

    if((decoded & GROUP_HEADER_NM_NUMBER_ENABLED) != 0) {
        nm->groupHeader.networkMessageNumberEnabled = true;
        rv |= _DECODE_BINARY(&nm->groupHeader.networkMessageNumber, UINT16);
    }

    if((decoded & GROUP_HEADER_SEQUENCE_NUMBER_ENABLED) != 0) {
        nm->groupHeader.sequenceNumberEnabled = true;
        rv |= _DECODE_BINARY(&nm->groupHeader.sequenceNumber, UINT16);
    }

    return rv;
}

static UA_StatusCode
UA_PayloadHeader_decodeBinary(PubSubDecodeCtx *ctx,
                              UA_NetworkMessage *nm) {
    if(nm->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    /* Decode the MessageCount */
    UA_Byte count;
    UA_StatusCode rv = _DECODE_BINARY(&count, BYTE);
    UA_CHECK_STATUS(rv, return rv);

    /* The NetworkMessage shall contain at least one DataSetMessage if the
     * NetworkMessage type is DataSetMessage payload. */
    if(count == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Limit for the inline-defined DataSetWriterIds */
    if(count > UA_NETWORKMESSAGE_MAXMESSAGECOUNT)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Decode the DataSetWriterIds */
    for(UA_Byte i = 0; i < count; i++) {
        rv |= _DECODE_BINARY(&nm->dataSetWriterIds[i], UINT16);
    }
    UA_CHECK_STATUS(rv, return rv);

    /* Set the MessageCount */
    nm->messageCount = count;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ExtendedNetworkMessageHeader_decodeBinary(PubSubDecodeCtx *ctx,
                                             UA_NetworkMessage* nm) {
    UA_StatusCode rv;

    /* Timestamp*/
    if(nm->timestampEnabled) {
        rv = _DECODE_BINARY(&nm->timestamp, DATETIME);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Picoseconds */
    if(nm->picosecondsEnabled) {
        rv = _DECODE_BINARY(&nm->picoseconds, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* PromotedFields */
    if(UA_LIKELY(!nm->promotedFieldsEnabled))
        return UA_STATUSCODE_GOOD;

    UA_UInt16 promotedFieldsLength; /* Size in bytes, not in number of fields */
    rv = _DECODE_BINARY(&promotedFieldsLength, UINT16);
    UA_CHECK_STATUS(rv, return rv);
    if(promotedFieldsLength == 0)
        return UA_STATUSCODE_GOOD;

    UA_Byte *endPos = ctx->ctx.pos + promotedFieldsLength;
    if(endPos > ctx->ctx.end)
        return UA_STATUSCODE_BADDECODINGERROR;
    
    size_t counter = 0;
    size_t space = 4;
    UA_Variant *pf = (UA_Variant*)
        ctxCalloc(&ctx->ctx, space, UA_TYPES[UA_TYPES_VARIANT].memSize);
    if(!pf)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    do {
        /* Increase the available space */
        if(counter == space) {
            UA_Variant *tmp = (UA_Variant*)
                ctxCalloc(&ctx->ctx, space << 1, UA_TYPES[UA_TYPES_VARIANT].memSize);
            if(!tmp) {
                if(!ctx->ctx.opts.calloc)
                    UA_Array_delete(pf, counter, &UA_TYPES[UA_TYPES_VARIANT]);
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            memcpy(tmp, pf, space * UA_TYPES[UA_TYPES_VARIANT].memSize);
            ctxFree(&ctx->ctx, pf);
            pf = tmp;
            space = space << 1;
        }

        /* Decode the PromotedField */
        rv = _DECODE_BINARY(&pf[counter], VARIANT);
        if(rv != UA_STATUSCODE_GOOD) {
            if(!ctx->ctx.opts.calloc)
                UA_Array_delete(pf, counter, &UA_TYPES[UA_TYPES_VARIANT]);
            return rv;
        }

        counter++;
    } while(ctx->ctx.pos < endPos);

    nm->promotedFields = pf;
    nm->promotedFieldsSize = (UA_UInt16)counter;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_SecurityHeader_decodeBinary(PubSubDecodeCtx *ctx,
                               UA_NetworkMessage* nm) {
    /* SecurityFlags */
    UA_Byte decoded;
    UA_StatusCode rv = _DECODE_BINARY(&decoded, BYTE);
    UA_CHECK_STATUS(rv, return rv);

    if((decoded & SECURITY_HEADER_NM_SIGNED) != 0)
        nm->securityHeader.networkMessageSigned = true;

    if((decoded & SECURITY_HEADER_NM_ENCRYPTED) != 0)
        nm->securityHeader.networkMessageEncrypted = true;

    if((decoded & SECURITY_HEADER_SEC_FOOTER_ENABLED) != 0)
        nm->securityHeader.securityFooterEnabled = true;

    if((decoded & SECURITY_HEADER_FORCE_KEY_RESET) != 0)
        nm->securityHeader.forceKeyReset = true;

    /* SecurityTokenId */
    rv = _DECODE_BINARY(&nm->securityHeader.securityTokenId, UINT32);
    UA_CHECK_STATUS(rv, return rv);

    /* MessageNonce */
    UA_Byte nonceLength;
    rv = _DECODE_BINARY(&nonceLength, BYTE);
    UA_CHECK_STATUS(rv, return rv);

    if(nonceLength > UA_NETWORKMESSAGE_MAX_NONCE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    if(nonceLength > 0) {
        nm->securityHeader.messageNonceSize = nonceLength;
        for(UA_Byte i = 0; i < nonceLength; i++) {
            rv = _DECODE_BINARY(&nm->securityHeader.messageNonce[i], BYTE);
            UA_CHECK_STATUS(rv, return rv);
        }
    }

    /* SecurityFooterSize */
    if(nm->securityHeader.securityFooterEnabled)
        rv = _DECODE_BINARY(&nm->securityHeader.securityFooterSize, UINT16);
    return rv;
}

/* If no PayloadHeader is defined, then assume the EncodingOptions reflect the
 * DataSetMessages. This can be used to inject an a-priori known number of
 * NetworkMessages and their DataSetWriterIds if the payload header is
 * disabled. */
void
UA_NetworkMessage_makeSyntheticPayloadHeader(const UA_NetworkMessage_EncodingOptions *eo,
                                             UA_NetworkMessage *nm) {
    UA_assert(nm->payloadHeaderEnabled == false);

    if(eo->metaDataSize > 0) {
        nm->messageCount = (UA_Byte)eo->metaDataSize;
        for(size_t i = 0; i < nm->messageCount; i++)
            nm->dataSetWriterIds[i] = eo->metaData[i].dataSetWriterId;
    } else {
        /* No Metadata configured and no payload header -> assume one
         * DataSetMessage. The NetworkMessage shall contain at least one
         * DataSetMessage if the NetworkMessage type is DataSetMessage
         * payload. */
        nm->messageCount = 1;
    }
}

UA_StatusCode
UA_NetworkMessage_decodeHeaders(PubSubDecodeCtx *ctx,
                                UA_NetworkMessage *nm) {
    UA_StatusCode rv = UA_NetworkMessageHeader_decodeBinary(ctx, nm);
    UA_CHECK_STATUS(rv, return rv);

    if(nm->groupHeaderEnabled) {
        rv = UA_GroupHeader_decodeBinary(ctx, nm);
        UA_CHECK_STATUS(rv, return rv);
    }

    if(nm->payloadHeaderEnabled) {
        rv = UA_PayloadHeader_decodeBinary(ctx, nm);
        UA_CHECK_STATUS(rv, return rv);
    }

    rv = UA_ExtendedNetworkMessageHeader_decodeBinary(ctx, nm);
    UA_CHECK_STATUS(rv, return rv);

    if(nm->securityEnabled)
        rv = UA_SecurityHeader_decodeBinary(ctx, nm);

    return rv;
}

UA_StatusCode
UA_NetworkMessage_decodePayload(PubSubDecodeCtx *ctx,
                                UA_NetworkMessage *nm) {
    /* Payload */
    if(nm->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    UA_assert(nm->messageCount > 0 &&
              nm->messageCount <= UA_NETWORKMESSAGE_MAXMESSAGECOUNT);

    /* Allocate the DataSetMessages */
    nm->payload.dataSetMessages = (UA_DataSetMessage*)
        ctxCalloc(&ctx->ctx, nm->messageCount, sizeof(UA_DataSetMessage));
    UA_CHECK_MEM(nm->payload.dataSetMessages,
                 return UA_STATUSCODE_BADOUTOFMEMORY);

    /* Get the payload sizes */
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    UA_UInt16 dataSetMessageSizes[UA_NETWORKMESSAGE_MAXMESSAGECOUNT];
    if(nm->messageCount == 1) {
        /* Not contained in the message, but can be inferred from the
         * remaining message length */
        UA_UInt16 size = (UA_UInt16)(ctx->ctx.end - ctx->ctx.pos);
        dataSetMessageSizes[0] = size;
    } else {
        if(nm->payloadHeaderEnabled) {
            /* Decode from the message */
            for(size_t i = 0; i < nm->messageCount; i++) {
                rv = _DECODE_BINARY(&dataSetMessageSizes[i], UINT16);
                UA_CHECK_STATUS(rv, return rv);
                if(dataSetMessageSizes[i] == 0)
                    return UA_STATUSCODE_BADDECODINGERROR;
            }
        } else {
            /* If no PayloadHeader is defined, then assume the EncodingOptions
             * reflect the DataSetMessages */
            for(size_t i = 0; i < nm->messageCount; i++)
                dataSetMessageSizes[i] = ctx->eo.metaData[i].configuredSize;
        }
    }

    /* Decode the DataSetMessages */
    for(size_t i = 0; i < nm->messageCount; i++) {
        const UA_DataSetMessage_EncodingMetaData *emd =
            findEncodingMetaData(&ctx->eo, nm->dataSetWriterIds[i]);
        rv |= UA_DataSetMessage_decodeBinary(ctx, emd,
                                             &nm->payload.dataSetMessages[i],
                                             dataSetMessageSizes[i]);
    }

    return rv;
}

UA_StatusCode
UA_NetworkMessage_decodeFooters(PubSubDecodeCtx *ctx,
                                UA_NetworkMessage *nm) {
    if(!nm->securityEnabled)
        return UA_STATUSCODE_GOOD;

    if(!nm->securityHeader.securityFooterEnabled ||
       nm->securityHeader.securityFooterSize == 0)
        return UA_STATUSCODE_GOOD;
    
    UA_StatusCode rv = UA_ByteString_allocBuffer(&nm->securityFooter,
                                                 nm->securityHeader.securityFooterSize);
    UA_CHECK_STATUS(rv, return rv);
    
    for(UA_UInt16 i = 0; i < nm->securityHeader.securityFooterSize; i++) {
        rv |= _DECODE_BINARY(&nm->securityFooter.data[i], BYTE);
    }
    return rv;
}

UA_StatusCode
UA_NetworkMessage_decodeBinary(const UA_ByteString *src,
                               UA_NetworkMessage* nm,
                               const UA_NetworkMessage_EncodingOptions *eo,
                               const UA_DecodeBinaryOptions *bo) {
    /* Initialize the decoding context */
    PubSubDecodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubDecodeCtx));
    ctx.ctx.pos = src->data;
    ctx.ctx.end = &src->data[src->length];
    ctx.ctx.depth = 0;
    if(eo)
        ctx.eo = *eo;
    if(bo)
        ctx.ctx.opts = *bo;

    /* headers only need to be decoded when not in encryption mode
     * because headers are already decoded when encryption mode is enabled
     * to check for security parameters and decrypt/verify
     *
     * TODO: check if there is a workaround to use this function
     *       also when encryption is enabled
     */
    // #ifndef UA_ENABLE_PUBSUB_ENCRYPTION
    // if(*offset == 0) {
    //    rv = UA_NetworkMessage_decodeHeaders(src, offset, nm);
    //    UA_CHECK_STATUS(rv, return rv);
    // }
    // #endif

    /* Initialize the NetworkMessage */
    memset(nm, 0, sizeof(UA_NetworkMessage));

    /* Decode the header */
    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(&ctx, nm);
    UA_CHECK_STATUS(rv, goto cleanup);

    /* Handle missing payload header and "inject" metadata */
    if(!nm->payloadHeaderEnabled)
        UA_NetworkMessage_makeSyntheticPayloadHeader(&ctx.eo, nm);

    /* Decode the payload */
    rv = UA_NetworkMessage_decodePayload(&ctx, nm);
    UA_CHECK_STATUS(rv, goto cleanup);

    /* Decode the footers */
    rv = UA_NetworkMessage_decodeFooters(&ctx, nm);
    UA_CHECK_STATUS(rv, goto cleanup);

cleanup:
    if(rv != UA_STATUSCODE_GOOD && !ctx.ctx.opts.calloc)
        UA_NetworkMessage_clear(nm);

    return rv;
}

UA_StatusCode
UA_NetworkMessage_decodeBinaryHeaders(const UA_ByteString *src,
                                      UA_NetworkMessage *dst,
                                      const UA_NetworkMessage_EncodingOptions *eo,
                                      const UA_DecodeBinaryOptions *bo,
                                      size_t *payloadOffset) {
    /* Initialize the decoding context */
    PubSubDecodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubDecodeCtx));
    ctx.ctx.pos = src->data;
    ctx.ctx.end = &src->data[src->length];
    ctx.ctx.depth = 0;
    if(eo)
        ctx.eo = *eo;
    if(bo)
        ctx.ctx.opts = *bo;

    /* Initialize the NetworkMessage */
    memset(dst, 0, sizeof(UA_NetworkMessage));

    /* Decode the headers */
    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(&ctx, dst);
    if(rv != UA_STATUSCODE_GOOD) {
        if(!ctx.ctx.opts.calloc)
            UA_NetworkMessage_clear(dst);
        return rv;
    }

    /* Handle missing payload header and "inject" metadata */
    if(!dst->payloadHeaderEnabled)
        UA_NetworkMessage_makeSyntheticPayloadHeader(&ctx.eo, dst);

    /* Set the offset */
    if(payloadOffset)
        *payloadOffset = (size_t)(ctx.ctx.pos - src->data);

    return rv;
}

static UA_Boolean
incrOffsetTable(UA_PubSubOffsetTable *ot) {
    UA_PubSubOffset *tmpOffsets = (UA_PubSubOffset *)
        UA_realloc(ot->offsets, sizeof(UA_PubSubOffset) * (ot->offsetsSize + 1));
    UA_CHECK_MEM(tmpOffsets, return false);
    memset(&tmpOffsets[ot->offsetsSize], 0, sizeof(UA_PubSubOffset));
    ot->offsets = tmpOffsets;
    ot->offsetsSize++;
    return true;
}

size_t
UA_NetworkMessage_calcSizeBinary(const UA_NetworkMessage *p,
                                 const UA_NetworkMessage_EncodingOptions *eo) {
    PubSubEncodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubEncodeCtx));
    if(eo)
        ctx.eo = *eo;
    return UA_NetworkMessage_calcSizeBinaryInternal(&ctx, p);
}

size_t
UA_NetworkMessage_calcSizeBinaryInternal(PubSubEncodeCtx *ctx,
                                         const UA_NetworkMessage *p) {
    UA_PubSubOffsetTable *ot = ctx->ot;

    size_t size = 1; /* byte */
    if(UA_NetworkMessage_ExtendedFlags1Enabled(p)) {
        size += 1; /* byte */
        if(UA_NetworkMessage_ExtendedFlags2Enabled(p))
            size += 1; /* byte */
    }

    if(p->publisherIdEnabled) {
        switch(p->publisherId.idType) {
            case UA_PUBLISHERIDTYPE_BYTE:
                size += 1; /* byte */
                break;
            case UA_PUBLISHERIDTYPE_UINT16:
                size += 2; /* uint16 */
                break;
            case UA_PUBLISHERIDTYPE_UINT32:
                size += 4; /* uint32 */
                break;
            case UA_PUBLISHERIDTYPE_UINT64:
                size += 8; /* uint64 */
                break;
            case UA_PUBLISHERIDTYPE_STRING:
                size += UA_String_calcSizeBinary(&p->publisherId.id.string);
                break;
        }
    }

    if(p->dataSetClassIdEnabled)
        size += 16; /* guid */

    /* Group Header */
    if(p->groupHeaderEnabled) {
        size += 1; /* byte */

        if(p->groupHeader.writerGroupIdEnabled)
            size += 2; /* UA_UInt16_calcSizeBinary(&p->groupHeader.writerGroupId) */

        if(p->groupHeader.groupVersionEnabled) {
            if(ot) {
                size_t pos = ot->offsetsSize;
                if(!incrOffsetTable(ot))
                    return 0;
                ot->offsets[pos].offset = size;
                ot->offsets[pos].offsetType =
                    UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_GROUPVERSION;
            }
            size += 4; /* UA_UInt32_calcSizeBinary(&p->groupHeader.groupVersion) */
        }

        if(p->groupHeader.networkMessageNumberEnabled) {
            size += 2; /* UA_UInt16_calcSizeBinary(&p->groupHeader.networkMessageNumber) */
        }

        if(p->groupHeader.sequenceNumberEnabled){
            if(ot){
                size_t pos = ot->offsetsSize;
                if(!incrOffsetTable(ot))
                    return 0;
                ot->offsets[pos].offset = size;
                ot->offsets[pos].offsetType =
                    UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER;
            }
            size += 2; /* UA_UInt16_calcSizeBinary(&p->groupHeader.sequenceNumber) */
        }
    }

    /* Payload Header */
    if(p->payloadHeaderEnabled) {
        if(p->networkMessageType != UA_NETWORKMESSAGE_DATASET)
            return 0; /* not implemented */
        size += 1; /* p->messageCount */
        size += (size_t)(2LU * p->messageCount); /* uint16 */
    }

    if(p->timestampEnabled) {
        if(ot) {
            size_t pos = ot->offsetsSize;
            if(!incrOffsetTable(ot))
                return 0;
            ot->offsets[pos].offset = size;
            ot->offsets[pos].offsetType = UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_TIMESTAMP;
        }
        size += 8; /* UA_DateTime_calcSizeBinary(&p->timestamp) */
    }

    if(p->picosecondsEnabled){
        if(ot) {
            size_t pos = ot->offsetsSize;
            if(!incrOffsetTable(ot))
                return 0;
            ot->offsets[pos].offset = size;
            ot->offsets[pos].offsetType = UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_PICOSECONDS;
        }
        size += 2; /* UA_UInt16_calcSizeBinary(&p->picoseconds) */
    }

    if(p->promotedFieldsEnabled) {
        size += 2; /* UA_UInt16_calcSizeBinary(&p->promotedFieldsSize) */
        for(UA_UInt16 i = 0; i < p->promotedFieldsSize; i++)
            size += UA_Variant_calcSizeBinary(&p->promotedFields[i]);
    }

    if(p->securityEnabled) {
        size += 1; /* UA_Byte_calcSizeBinary(&byte) */
        size += 4; /* UA_UInt32_calcSizeBinary(&p->securityHeader.securityTokenId) */
        size += 1; /* UA_Byte_calcSizeBinary(&p->securityHeader.nonceLength) */
        size += p->securityHeader.messageNonceSize;
        if(p->securityHeader.securityFooterEnabled)
            size += 2; /* UA_UInt16_calcSizeBinary(&p->securityHeader.securityFooterSize) */
    }

    /* Encode the payload */
    if(p->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return 0; /* not implemented */

    UA_Byte count = p->messageCount;
    if(p->payloadHeaderEnabled && count > 1)
        size += (size_t)(2LU * count); /* DataSetMessagesSize (uint16) */
    for(size_t i = 0; i < count; i++) {
        /* Add the offset here and not inside UA_DataSetMessage_calcSizeBinary.
         * We don't want the offset marking the beginning of the DataSetMessage
         * if we compute the offsets of a single DataSetMessage (without looking
         * at the entire NetworkMessage). */
        if(ot) {
            size_t pos = ot->offsetsSize;
            if(!incrOffsetTable(ot))
                return 0;
            ot->offsets[pos].offset = size;
            ot->offsets[pos].offsetType = UA_PUBSUBOFFSETTYPE_DATASETMESSAGE;
        }

        /* size = ... as the original size is used as the starting point in
         * UA_DataSetMessage_calcSizeBinary */
        UA_DataSetMessage *dsm = &p->payload.dataSetMessages[i];
        const UA_DataSetMessage_EncodingMetaData *emd =
            findEncodingMetaData(&ctx->eo, p->dataSetWriterIds[i]);
        size = UA_DataSetMessage_calcSizeBinary(ctx, emd, dsm, size);
        if(size == 0)
            return 0;
    }

    if(p->securityEnabled && p->securityHeader.securityFooterEnabled)
        size += p->securityHeader.securityFooterSize;

    return size;
}

void
UA_NetworkMessage_clear(UA_NetworkMessage* p) {
    if(p->promotedFieldsEnabled) {
        UA_Array_delete(p->promotedFields, p->promotedFieldsSize,
                        &UA_TYPES[UA_TYPES_VARIANT]);
    }

    if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
        if(p->payload.dataSetMessages) {
            for(size_t i = 0; i < p->messageCount; i++)
                UA_DataSetMessage_clear(&p->payload.dataSetMessages[i]);
            UA_free(p->payload.dataSetMessages);
        }
    }

    UA_ByteString_clear(&p->securityFooter);
    UA_String_clear(&p->messageId);

    if(p->publisherIdEnabled &&
       p->publisherId.idType == UA_PUBLISHERIDTYPE_STRING)
       UA_String_clear(&p->publisherId.id.string);

    memset(p, 0, sizeof(UA_NetworkMessage));
}

UA_Boolean
UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessage* src) {
    if(src->publisherId.idType != UA_PUBLISHERIDTYPE_BYTE ||
       src->dataSetClassIdEnabled || src->securityEnabled ||
       src->timestampEnabled || src->picosecondsEnabled ||
       UA_NetworkMessage_ExtendedFlags2Enabled(src))
        return true;
    return false;
}

UA_Boolean
UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src) {
    if(src->chunkMessage || src->promotedFieldsEnabled ||
       src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return true;
    return false;
}

UA_Boolean
UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src) {
    if(src->dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME ||
       src->timestampEnabled || src->picoSecondsIncluded)
        return true;
    return false;
}

UA_StatusCode
UA_DataSetMessageHeader_encodeBinary(PubSubEncodeCtx *ctx,
                                     const UA_DataSetMessageHeader *src) {
    UA_Byte v;
    /* DataSetFlags1 */
    v = (UA_Byte)src->fieldEncoding;
    /* shift left 1 bit */
    v = (UA_Byte)(v << DS_MH_SHIFT_LEN);

    if(src->dataSetMessageValid)
        v |= DS_MESSAGEHEADER_DS_MSG_VALID;

    if(src->dataSetMessageSequenceNrEnabled)
        v |= DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK;

    if(src->statusEnabled)
        v |= DS_MESSAGEHEADER_STATUS_ENABLED_MASK;

    if(src->configVersionMajorVersionEnabled)
        v |= DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK;

    if(src->configVersionMinorVersionEnabled)
        v |= DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK;

    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(src))
        v |= DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK;

    UA_StatusCode rv = _ENCODE_BINARY(&v, BYTE);
    UA_CHECK_STATUS(rv, return rv);

    /* DataSetFlags2 */
    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(src)) {
        v = (UA_Byte)src->dataSetMessageType;

        if(src->timestampEnabled)
            v |= DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK;

        if(src->picoSecondsIncluded)
            v |= DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK;

        rv = _ENCODE_BINARY(&v, BYTE);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* DataSetMessageSequenceNr */
    if(src->dataSetMessageSequenceNrEnabled) {
        rv = _ENCODE_BINARY(&src->dataSetMessageSequenceNr, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Timestamp */
    if(src->timestampEnabled) {
        rv = _ENCODE_BINARY(&src->timestamp, DATETIME);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* PicoSeconds */
    if(src->picoSecondsIncluded) {
        rv = _ENCODE_BINARY(&src->picoSeconds, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Status */
    if(src->statusEnabled) {
        rv = _ENCODE_BINARY(&src->status, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* ConfigVersionMajorVersion */
    if(src->configVersionMajorVersionEnabled) {
        rv = _ENCODE_BINARY(&src->configVersionMajorVersion, UINT32);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* ConfigVersionMinorVersion */
    if(src->configVersionMinorVersionEnabled) {
        rv = _ENCODE_BINARY(&src->configVersionMinorVersion, UINT32);
        UA_CHECK_STATUS(rv, return rv);
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode,
                              UA_PubSubSecurityPolicy *sp, void *policyContext,
                              UA_Byte *messageStart, UA_Byte *encryptStart,
                              UA_Byte *sigStart) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Encrypt the payload */
    if(securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        /* Set the temporary MessageNonce in the SecurityPolicy */
        const UA_ByteString nonce = {
            (size_t)nm->securityHeader.messageNonceSize,
            nm->securityHeader.messageNonce
        };
        res = sp->setMessageNonce(sp, policyContext, &nonce);
        UA_CHECK_STATUS(res, return res);

        /* The encryption is done in-place, no need to encode again */
        UA_ByteString encryptBuf;
        encryptBuf.data = encryptStart;
        encryptBuf.length = (uintptr_t)sigStart - (uintptr_t)encryptStart;
        res = sp->encrypt(sp, policyContext, &encryptBuf);
        UA_CHECK_STATUS(res, return res);
    }

    /* Sign the entire message */
    if(securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        UA_ByteString sigBuf;
        sigBuf.length = (uintptr_t)sigStart - (uintptr_t)messageStart;
        sigBuf.data = messageStart;
        size_t sigSize = sp->getSignatureSize(sp, policyContext);
        UA_ByteString sig = {sigSize, sigStart};
        res = sp->sign(sp, policyContext, &sigBuf, &sig);
    }

    return res;
}

UA_StatusCode
UA_DataSetMessageHeader_decodeBinary(PubSubDecodeCtx *ctx,
                                     UA_DataSetMessageHeader* dsmh) {
    UA_Byte v;
    UA_StatusCode rv = _DECODE_BINARY(&v, BYTE);
    UA_CHECK_STATUS(rv, return rv);

    UA_Byte v2 = v & DS_MESSAGEHEADER_FIELD_ENCODING_MASK;
    v2 = (UA_Byte)(v2 >> DS_MH_SHIFT_LEN);
    dsmh->fieldEncoding = (UA_FieldEncoding)v2;

    if((v & DS_MESSAGEHEADER_DS_MSG_VALID) != 0)
        dsmh->dataSetMessageValid = true;

    if((v & DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK) != 0)
        dsmh->dataSetMessageSequenceNrEnabled = true;

    if((v & DS_MESSAGEHEADER_STATUS_ENABLED_MASK) != 0)
        dsmh->statusEnabled = true;

    if((v & DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK) != 0)
        dsmh->configVersionMajorVersionEnabled = true;

    if((v & DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK) != 0)
        dsmh->configVersionMinorVersionEnabled = true;

    if((v & DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK) != 0) {
        rv = _DECODE_BINARY(&v, BYTE);
        UA_CHECK_STATUS(rv, return rv);

        dsmh->dataSetMessageType = (UA_DataSetMessageType)(v & DS_MESSAGEHEADER_DS_MESSAGE_TYPE_MASK);

        if((v & DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK) != 0)
            dsmh->timestampEnabled = true;

        if((v & DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK) != 0)
            dsmh->picoSecondsIncluded = true;
    }
    /* The else-case is implied as dsmh is zeroed-out initially:
     * else {
     * dsmh->dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
     *   dsmh->picoSecondsIncluded = false;
     * } */

    if(dsmh->dataSetMessageSequenceNrEnabled) {
        rv = _DECODE_BINARY(&dsmh->dataSetMessageSequenceNr, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dsmh->dataSetMessageSequenceNr = 0;
    }

    if(dsmh->timestampEnabled) {
        rv = _DECODE_BINARY(&dsmh->timestamp, DATETIME);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dsmh->timestamp = 0;
    }

    if(dsmh->picoSecondsIncluded) {
        rv = _DECODE_BINARY(&dsmh->picoSeconds, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dsmh->picoSeconds = 0;
    }

    if(dsmh->statusEnabled) {
        rv = _DECODE_BINARY(&dsmh->status, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dsmh->status = 0;
    }

    if(dsmh->configVersionMajorVersionEnabled) {
        rv = _DECODE_BINARY(&dsmh->configVersionMajorVersion, UINT32);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dsmh->configVersionMajorVersion = 0;
    }

    if(dsmh->configVersionMinorVersionEnabled) {
        rv = _DECODE_BINARY(&dsmh->configVersionMinorVersion, UINT32);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dsmh->configVersionMinorVersion = 0;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataSetMessage_keyFrame_rawScalar_encodeBinary(PubSubEncodeCtx *ctx,
                                                  const UA_FieldMetaData *fmd,
                                                  void *p, const UA_DataType *type) {
    /* TODO: Padding not yet supported for strings inside structures */
    UA_StatusCode rv = encodeBinaryJumpTable[type->typeKind](&ctx->ctx, p, type);
    UA_CHECK_STATUS(rv, return rv);
    if(fmd && fmd->maxStringLength != 0 &&
       (type->typeKind == UA_DATATYPEKIND_STRING ||
        type->typeKind == UA_DATATYPEKIND_BYTESTRING)) {
        UA_String *str = (UA_String *)p;
        if(str->length > fmd->maxStringLength)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        size_t padding = fmd->maxStringLength - str->length;
        memset(ctx->ctx.pos, 0, padding);
        ctx->ctx.pos += padding;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataSetMessage_keyFrame_raw_encodeBinary(PubSubEncodeCtx *ctx,
                                            const UA_FieldMetaData *fmd,
                                            const UA_Variant *v) {
    if(!v->type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Scalar encoding */
    if(UA_Variant_isScalar(v))
        return UA_DataSetMessage_keyFrame_rawScalar_encodeBinary(ctx, fmd, v->data, v->type);

    /* Set up the Arraydimensions of the value.
     * No defined ArrayDimensions -> use one-dimensional */
    UA_UInt32 tmpDim;
    UA_UInt32 *arrayDims = v->arrayDimensions;
    size_t arrayDimsSize = v->arrayDimensionsSize;
    if(!arrayDims) {
        tmpDim = (UA_UInt32)v->arrayLength;
        arrayDims = &tmpDim;
        arrayDimsSize = 1;
    }

    /* Verify the value-arraydimensions match the fmd->arraydimensions.
     * TODO: Fill up with padding when the content is lacking. */
    if(fmd && fmd->arrayDimensionsSize > 0) {
        if(fmd->arrayDimensionsSize != arrayDimsSize)
            return UA_STATUSCODE_BADENCODINGERROR;
        for(size_t i = 0; i < arrayDimsSize; i++) {
            if(arrayDims[i] != fmd->arrayDimensions[i])
                return UA_STATUSCODE_BADENCODINGERROR;
        }
    }

    /* For arrays encode the dimension sizes before the actual data */
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < arrayDimsSize; i++) {
        rv |= _ENCODE_BINARY(&arrayDims[i], UINT32);
    }
    UA_CHECK_STATUS(rv, return rv);

    /* Encode the array of values */
    uintptr_t valuePtr = (uintptr_t)v->data;
    for(size_t i = 0; i < v->arrayLength; i++) {
        rv = UA_DataSetMessage_keyFrame_rawScalar_encodeBinary(ctx, fmd,
                                                               (void*)valuePtr, v->type);
        UA_CHECK_STATUS(rv, return rv);
        valuePtr += v->type->memSize;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataSetMessage_keyFrame_encodeBinary(PubSubEncodeCtx *ctx,
                                        const UA_DataSetMessage_EncodingMetaData *emd,
                                        const UA_DataSetMessage *src) {
    /* Heartbeat: "DataSetMessage is a key frame that only contains header
     * information" */
    if(src->fieldCount == 0)
        return UA_STATUSCODE_GOOD;

    /* Part 14: The FieldCount shall be omitted if RawData field encoding is set */
    UA_StatusCode rv = UA_STATUSCODE_BADINTERNALERROR;
    if(src->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) {
        rv = _ENCODE_BINARY(&src->fieldCount, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    }
    
    for(UA_UInt16 i = 0; i < src->fieldCount; i++) {
        const UA_DataValue *v = &src->data.keyFrameFields[i];
        if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
            rv = _ENCODE_BINARY(&v->value, VARIANT);
        } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
            rv = _ENCODE_BINARY(v, DATAVALUE);
        } else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
            const UA_FieldMetaData *fmd = getFieldMetaData(emd, i);
            rv = UA_DataSetMessage_keyFrame_raw_encodeBinary(ctx, fmd, &v->value);
        } else {
            rv = UA_STATUSCODE_BADENCODINGERROR;
        }
        UA_CHECK_STATUS(rv, return rv);
    }
    return rv;
}

static UA_StatusCode
UA_DataSetMessage_deltaFrame_encodeBinary(PubSubEncodeCtx *ctx,
                                          const UA_DataSetMessage* src) {
    if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    /* Here the FieldCount is always present */
    UA_StatusCode rv = _ENCODE_BINARY(&src->fieldCount, UINT16);
    if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
        for(UA_UInt16 i = 0; i < src->fieldCount; i++) {
            rv |= _ENCODE_BINARY(&src->data.deltaFrameFields[i].index, UINT16);
            rv |= _ENCODE_BINARY(&src->data.deltaFrameFields[i].value.value, VARIANT);
        }
    } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
        for(UA_UInt16 i = 0; i < src->fieldCount; i++) {
            rv |= _ENCODE_BINARY(&src->data.deltaFrameFields[i].index, UINT16);
            rv |= _ENCODE_BINARY(&src->data.deltaFrameFields[i].value, DATAVALUE);
        }
    }
    return rv;
}

UA_StatusCode
UA_DataSetMessage_encodeBinary(PubSubEncodeCtx *ctx,
                               const UA_DataSetMessage_EncodingMetaData *emd,
                               const UA_DataSetMessage* src) {
    /* Store the beginning */
    UA_Byte *begin = ctx->ctx.pos;
    
    /* Encode Header */
    UA_StatusCode rv = UA_DataSetMessageHeader_encodeBinary(ctx, &src->header);
    UA_CHECK_STATUS(rv, return rv);

    /* Encode Payload */
    switch(src->header.dataSetMessageType) {
    case UA_DATASETMESSAGE_DATAKEYFRAME:
        rv = UA_DataSetMessage_keyFrame_encodeBinary(ctx, emd, src);
        break;
    case UA_DATASETMESSAGE_DATADELTAFRAME:
        rv = UA_DataSetMessage_deltaFrame_encodeBinary(ctx, src);
        break;
    case UA_DATASETMESSAGE_KEEPALIVE:
        break; /* Keep-Alive Message contains no Payload Data */
    default:
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    /* Zero-Padding according to a ConfiguredSize */
    if(emd && emd->configuredSize > 0 && src->header.dataSetMessageValid) {
        UA_Byte *configuredEnd = begin + emd->configuredSize;
        if(configuredEnd > ctx->ctx.end)
            return UA_STATUSCODE_BADENCODINGERROR;
        if(configuredEnd > ctx->ctx.pos) {
            size_t padding = (size_t)(configuredEnd - ctx->ctx.pos);
            memset(ctx->ctx.pos, 0, padding);
            ctx->ctx.pos += padding;
        }
    }
    UA_CHECK_STATUS(rv, return rv);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
decodeRawField(PubSubDecodeCtx *ctx,
               const UA_FieldMetaData *fmd,
               UA_DataValue *value) {
    if(!fmd)
        return UA_STATUSCODE_BADDECODINGERROR;
    const UA_DataType *type =
        UA_findDataTypeWithCustom(&fmd->dataType, ctx->ctx.opts.customTypes);
    if(!type) {
        if(fmd->builtInType == 0 ||
           fmd->builtInType > UA_DATATYPEKIND_DIAGNOSTICINFO + 1)
            return UA_STATUSCODE_BADDECODINGERROR;
        type = &UA_TYPES[fmd->builtInType - 1];
    }

    /* The ValueRank must be scalar or a defined dimensionality */
    if(fmd->valueRank < -1 || fmd->valueRank == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    value->hasValue = true;
    value->value.type = type;

    /* Scalar */
    if(fmd->valueRank == -1) {
        value->value.data = ctxCalloc(&ctx->ctx, 1, type->memSize);
        if(!value->value.data)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        return decodeBinaryJumpTable[type->typeKind](&ctx->ctx, value->value.data, type);
    }

    /* Decode the ArrayDimensions */
    value->value.arrayDimensions = (UA_UInt32*)
        ctxCalloc(&ctx->ctx, fmd->arrayDimensionsSize, sizeof(UA_UInt32));
    if(!value->value.arrayDimensions)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    value->value.arrayDimensionsSize = fmd->arrayDimensionsSize;

    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < fmd->arrayDimensionsSize; i++) {
        rv |= _DECODE_BINARY(&value->value.arrayDimensions[i], UINT32);
    }
    UA_CHECK_STATUS(rv, return rv);

    /* Validate the ArrayDimensions and prepare the total count */
    size_t count = 1;
    for(size_t i = 0; i < fmd->arrayDimensionsSize; i++) {
        if(value->value.arrayDimensions[i] == 0 ||
           value->value.arrayDimensions[i] > fmd->arrayDimensions[i])
            return UA_STATUSCODE_BADDECODINGERROR;
        count *= value->value.arrayDimensions[i];
    }

    /* Allocate the array memory */
    value->value.data = ctxCalloc(&ctx->ctx, count, type->memSize);
    if(!value->value.data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode the content */
    uintptr_t val = (uintptr_t)value->value.data;
    for(size_t i = 0; i < count; i++) {
        rv |= decodeBinaryJumpTable[type->typeKind](&ctx->ctx, (void*)val, type);
        val += type->memSize;
    }

    return rv;
}

static UA_StatusCode
UA_DataSetMessage_keyFrame_decodeBinary(PubSubDecodeCtx *ctx,
                                        const UA_DataSetMessage_EncodingMetaData *emd,
                                        UA_DataSetMessage *dsm) {
    UA_StatusCode rv = UA_STATUSCODE_GOOD;

    /* Part 14: The FieldCount shall be omitted if RawData field encoding is set */
    if(dsm->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) {
        rv = _DECODE_BINARY(&dsm->fieldCount, UINT16);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        if(!emd)
            return UA_STATUSCODE_BADDECODINGERROR;
        dsm->fieldCount = (UA_UInt16)emd->fieldsSize;
    }

    if(dsm->fieldCount == 0)
        return UA_STATUSCODE_GOOD; /* Heartbeat */

    dsm->data.keyFrameFields = (UA_DataValue *)
        ctxCalloc(&ctx->ctx, dsm->fieldCount, sizeof(UA_DataValue));
    if(!dsm->data.keyFrameFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    switch(dsm->header.fieldEncoding) {
    case UA_FIELDENCODING_VARIANT:
        for(UA_UInt16 i = 0; i < dsm->fieldCount; i++) {
            rv = _DECODE_BINARY(&dsm->data.keyFrameFields[i].value, VARIANT);
            UA_CHECK_STATUS(rv, return rv);
            dsm->data.keyFrameFields[i].hasValue = true;
        }
        break;

    case UA_FIELDENCODING_DATAVALUE:
        for(UA_UInt16 i = 0; i < dsm->fieldCount; i++) {
            rv = _DECODE_BINARY(&dsm->data.keyFrameFields[i], DATAVALUE);
            UA_CHECK_STATUS(rv, return rv);
        }
        break;

    case UA_FIELDENCODING_RAWDATA: {
        for(UA_UInt16 i = 0; i < dsm->fieldCount; i++) {
            const UA_FieldMetaData *fmd = getFieldMetaData(emd, i);
            rv = decodeRawField(ctx, fmd, &dsm->data.keyFrameFields[i]);
            UA_CHECK_STATUS(rv, return rv);
        }
        break;
    }

    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    return rv;
}

static UA_StatusCode
UA_DataSetMessage_deltaFrame_decodeBinary(PubSubDecodeCtx *ctx,
                                          UA_DataSetMessage *dsm) {
    if(dsm->header.fieldEncoding == UA_FIELDENCODING_RAWDATA)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    if(dsm->header.fieldEncoding != UA_FIELDENCODING_VARIANT &&
       dsm->header.fieldEncoding != UA_FIELDENCODING_DATAVALUE)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode rv = _DECODE_BINARY(&dsm->fieldCount, UINT16);
    UA_CHECK_STATUS(rv, return rv);

    dsm->data.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField *)
        ctxCalloc(&ctx->ctx, dsm->fieldCount, sizeof(UA_DataSetMessage_DeltaFrameField));
    if(!dsm->data.deltaFrameFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    for(UA_UInt16 i = 0; i < dsm->fieldCount; i++) {
        rv = _DECODE_BINARY(&dsm->data.deltaFrameFields[i].index, UINT16);
        UA_CHECK_STATUS(rv, return rv);
        if(dsm->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
            rv = _DECODE_BINARY(&dsm->data.deltaFrameFields[i].value.value, VARIANT);
            UA_CHECK_STATUS(rv, return rv);
            dsm->data.deltaFrameFields[i].value.hasValue = true;
        } else {
            rv = _DECODE_BINARY(&dsm->data.deltaFrameFields[i].value, DATAVALUE);
            UA_CHECK_STATUS(rv, return rv);
        }
    }

    return rv;
}

UA_StatusCode
UA_DataSetMessage_decodeBinary(PubSubDecodeCtx *ctx,
                               const UA_DataSetMessage_EncodingMetaData *em,
                               UA_DataSetMessage *dsm,
                               size_t dsmSize) {
    UA_Byte *begin = ctx->ctx.pos;
    UA_StatusCode rv = UA_DataSetMessageHeader_decodeBinary(ctx, &dsm->header);
    UA_CHECK_STATUS(rv, return rv);
    switch(dsm->header.dataSetMessageType) {
    case UA_DATASETMESSAGE_DATAKEYFRAME:
        rv = UA_DataSetMessage_keyFrame_decodeBinary(ctx, em, dsm);
        break;
    case UA_DATASETMESSAGE_DATADELTAFRAME:
        rv = UA_DataSetMessage_deltaFrame_decodeBinary(ctx, dsm);
        break;
    case UA_DATASETMESSAGE_KEEPALIVE:
        return UA_STATUSCODE_GOOD; /* Keep-Alive Message contains no Payload Data */
    default:
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    /* If the message could not be decoded (e.g. no metadata for the raw
     * encoding), but technically the message is not fauly, jump to the next
     * dsm. */
    if(!dsm->header.dataSetMessageValid) {
        if(dsmSize == 0) /* Only possible if the size is known */
            return UA_STATUSCODE_BADDECODINGERROR;
        ctx->ctx.pos = begin + dsmSize;
    }
    return rv;
}

static size_t
UA_DataSetMessage_rawScalar_calcSizeBinary(void *p, const UA_DataType *type,
                                           const UA_FieldMetaData *fmd,
                                           size_t size) {
    /* TODO: Padding not yet supported for strings inside structures */
    size += UA_calcSizeBinary(p, type, NULL);
    if(fmd && fmd->maxStringLength != 0 &&
       (type->typeKind == UA_DATATYPEKIND_STRING ||
        type->typeKind == UA_DATATYPEKIND_BYTESTRING)) {
        UA_String *str = (UA_String *)p;
        if(str->length > fmd->maxStringLength)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        size_t padding = fmd->maxStringLength - str->length;
        size += padding;
    }
    return size;
}

static size_t
UA_DataSetMessage_raw_calcSizeBinary(const UA_Variant *v, const UA_FieldMetaData *fmd,
                                     UA_PubSubOffsetTable *ot, size_t size) {
    if(!v->type || !fmd)
        return 0;

    /* Scalar encoding */
    if(UA_Variant_isScalar(v))
        return UA_DataSetMessage_rawScalar_calcSizeBinary(v->data, v->type, fmd, size);

    /* Set up the Arraydimensions of the value.
     * No defined ArrayDimensions -> use one-dimensional */
    UA_UInt32 tmpDim;
    UA_UInt32 *arrayDims = v->arrayDimensions;
    size_t arrayDimsSize = v->arrayDimensionsSize;
    if(!arrayDims) {
        tmpDim = (UA_UInt32)v->arrayLength;
        arrayDims = &tmpDim;
        arrayDimsSize = 1;
    }

    /* Verify the value-arraydimensions match the fmd->arraydimensions.
     * TODO: Fill up with padding when the content is lacking. */
    if(fmd->arrayDimensionsSize > 0) {
        if(fmd->arrayDimensionsSize != arrayDimsSize)
            return 0;
        for(size_t i = 0; i < arrayDimsSize; i++) {
            if(arrayDims[i] != fmd->arrayDimensions[i])
                return 0;
        }
    }

    /* For arrays add the dimension sizes before the actual data */
    size += arrayDimsSize * sizeof(UA_UInt32);
    if(ot) {
        /* Start the offset at beginning of the payload, after the dimensions */
        UA_PubSubOffset *offset = &ot->offsets[ot->offsetsSize-1];
        offset->offset += arrayDimsSize * sizeof(UA_UInt32);
    }

    /* Add the array of values */
    uintptr_t valuePtr = (uintptr_t)v->data;
    for(size_t i = 0; i < v->arrayLength; i++) {
        size = UA_DataSetMessage_rawScalar_calcSizeBinary((void*)valuePtr, v->type, fmd, size);
        if(size == 0)
            return 0;
        valuePtr += v->type->memSize;
    }
    return size;
}

size_t
UA_DataSetMessage_calcSizeBinary(PubSubEncodeCtx *ctx,
                                 const UA_DataSetMessage_EncodingMetaData *emd,
                                 UA_DataSetMessage *p,
                                 size_t size) {
    UA_PubSubOffsetTable *ot = ctx->ot;

    size += 1; /* byte: DataSetMessage Type + Flags */
    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(&p->header))
        size += 1; /* byte */

    if(p->header.dataSetMessageSequenceNrEnabled) {
        if(ot) {
            size_t pos = ot->offsetsSize;
            if(!incrOffsetTable(ot))
                return 0;
            ot->offsets[pos].offset = size;
            ot->offsets[pos].offsetType = UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER;
        }
        size += 2; /* UA_UInt16_calcSizeBinary(&p->header.dataSetMessageSequenceNr) */
    }

    if(p->header.timestampEnabled) {
        if(ot) {
            size_t pos = ot->offsetsSize;
            if(!incrOffsetTable(ot))
                return 0;
            ot->offsets[pos].offset = size;
            ot->offsets[pos].offsetType = UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_TIMESTAMP;
        }
        size += 8; /* UA_DateTime_calcSizeBinary(&p->header.timestamp) */
    }

    if(p->header.picoSecondsIncluded) {
        if(ot) {
            size_t pos = ot->offsetsSize;
            if(!incrOffsetTable(ot))
                return 0;
            ot->offsets[pos].offset = size;
            ot->offsets[pos].offsetType = UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_PICOSECONDS;
        }
        size += 2; /* UA_UInt16_calcSizeBinary(&p->header.picoSeconds) */
    }

    if(p->header.statusEnabled) {
        if(ot) {
            size_t pos = ot->offsetsSize;
            if(!incrOffsetTable(ot))
                return 0;
            ot->offsets[pos].offset = size;
            ot->offsets[pos].offsetType = UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_STATUS;
        }
        size += 2; /* UA_UInt16_calcSizeBinary(&p->header.status) */
    }

    if(p->header.configVersionMajorVersionEnabled)
        size += 4; /* UA_UInt32_calcSizeBinary(&p->header.configVersionMajorVersion) */

    if(p->header.configVersionMinorVersionEnabled)
        size += 4; /* UA_UInt32_calcSizeBinary(&p->header.configVersionMinorVersion) */

    /* Keyframe with no fields is a heartbeat */
    if(p->header.dataSetMessageType == UA_DATASETMESSAGE_KEEPALIVE ||
       (p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME && p->fieldCount == 0))
        return size;

    if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
        if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA)
            size += 2; /* p->data.keyFrameData.fieldCount */

        for(UA_UInt16 i = 0; i < p->fieldCount; i++){
            if(!p->data.keyFrameFields)
                return 0;
            UA_PubSubOffset *offset = NULL;
            const UA_DataValue *v = &p->data.keyFrameFields[i];
            if(ot) {
                size_t pos = ot->offsetsSize;
                if(!incrOffsetTable(ot))
                    return 0;
                offset = &ot->offsets[pos];
                offset->offset = size;
                if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
                    offset->offsetType = UA_PUBSUBOFFSETTYPE_DATASETFIELD_VARIANT;
                } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
                    if(!v->value.type || !v->value.type->pointerFree)
                        return 0; /* only integer types for now */
                    offset->offsetType = UA_PUBSUBOFFSETTYPE_DATASETFIELD_RAW;
                } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
                    offset->offsetType = UA_PUBSUBOFFSETTYPE_DATASETFIELD_DATAVALUE;
                }
            }

            if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
                size += UA_calcSizeBinary(&v->value, &UA_TYPES[UA_TYPES_VARIANT], NULL);
            } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
                const UA_FieldMetaData *fmd = getFieldMetaData(emd, i);
                size = UA_DataSetMessage_raw_calcSizeBinary(&v->value, fmd, ot, size);
            } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
                size += UA_calcSizeBinary(v, &UA_TYPES[UA_TYPES_DATAVALUE], NULL);
            } else {
                return 0;
            }
        }
    } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) {
        if(ot)
            return 0; /* Not supported for RT */

        if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA)
            return 0; /* not supported */

        size += 2; /* p->data.deltaFrameData.fieldCount */
        size += (size_t)(2LU * p->fieldCount); /* index per field */

        for(UA_UInt16 i = 0; i < p->fieldCount; i++) {
            const UA_DataValue *v = &p->data.deltaFrameFields[i].value;
            if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT)
                size += UA_calcSizeBinary(&v->value, &UA_TYPES[UA_TYPES_VARIANT], NULL);
            else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE)
                size += UA_calcSizeBinary(v, &UA_TYPES[UA_TYPES_DATAVALUE], NULL);
        }
    } else {
        /* Unknown message type */
        return 0;
    }

    /* Minimum message size configured.
     * If the message is larger than the configuredSize, it shall be set to not valid. */
    if(emd && emd->configuredSize > 0) {
        if(emd->configuredSize < size) 
            p->header.dataSetMessageValid = false;
        size = emd->configuredSize;
    }
    
    return size;
}

void
UA_DataSetMessage_clear(UA_DataSetMessage* p) {
    if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
        if(p->data.keyFrameFields)
            UA_Array_delete(p->data.keyFrameFields, p->fieldCount,
                            &UA_TYPES[UA_TYPES_DATAVALUE]);
    } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) {
        if(p->data.deltaFrameFields) {
            for(UA_UInt16 i = 0; i < p->fieldCount; i++)
                UA_DataValue_clear(&p->data.deltaFrameFields[i].value);
            UA_free(p->data.deltaFrameFields);
        }
    }

    memset(p, 0, sizeof(UA_DataSetMessage));
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_connection.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2025 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019, 2022, 2024 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

static UA_Boolean
UA_PubSubConnection_canConnect(UA_PubSubConnection *c);

static UA_StatusCode
UA_PubSubConnection_connect(UA_PubSubManager *psm, UA_PubSubConnection *c,
                            UA_Boolean validate);

static void
UA_PubSubConnection_process(UA_PubSubManager *psm, UA_PubSubConnection *c,
                            const UA_ByteString msg);

static void
UA_PubSubConnection_disconnect(UA_PubSubConnection *c);

UA_StatusCode
UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src,
                               UA_PubSubConnectionConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_PubSubConnectionConfig));
    res |= UA_PublisherId_copy(&src->publisherId, &dst->publisherId);
    res |= UA_String_copy(&src->name, &dst->name);
    res |= UA_Variant_copy(&src->address, &dst->address);
    res |= UA_String_copy(&src->transportProfileUri, &dst->transportProfileUri);
    res |= UA_Variant_copy(&src->connectionTransportSettings,
                           &dst->connectionTransportSettings);
    res |= UA_KeyValueMap_copy(&src->connectionProperties,
                               &dst->connectionProperties);
    if(res != UA_STATUSCODE_GOOD)
        UA_PubSubConnectionConfig_clear(dst);
    return res;
}

UA_PubSubConnection *
UA_PubSubConnection_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        if(UA_NodeId_equal(&id, &c->head.identifier))
            break;
    }
    return c;
}

void
UA_PubSubConnectionConfig_clear(UA_PubSubConnectionConfig *connectionConfig) {
    UA_PublisherId_clear(&connectionConfig->publisherId);
    UA_String_clear(&connectionConfig->name);
    UA_String_clear(&connectionConfig->transportProfileUri);
    UA_Variant_clear(&connectionConfig->connectionTransportSettings);
    UA_Variant_clear(&connectionConfig->address);
    UA_KeyValueMap_clear(&connectionConfig->connectionProperties);
}

UA_StatusCode
UA_PubSubConnection_create(UA_PubSubManager *psm, const UA_PubSubConnectionConfig *cc,
                           UA_NodeId *cId) {
    /* Allocate */
    UA_PubSubConnection *c = (UA_PubSubConnection*)
        UA_calloc(1, sizeof(UA_PubSubConnection));
    if(!c)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    c->head.componentType = UA_PUBSUBCOMPONENT_CONNECTION;

    /* Copy the connection config */
    UA_StatusCode ret = UA_PubSubConnectionConfig_copy(cc, &c->config);
    UA_CHECK_STATUS(ret, UA_free(c); return ret);

    /* Assign the connection identifier */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    /* Internally create a unique id */
    addPubSubConnectionRepresentation(psm->sc.server, c);
#else
    /* Create a unique NodeId that does not correspond to a Node */
    UA_PubSubManager_generateUniqueNodeId(psm, &c->head.identifier);
#endif

    /* Register */
    TAILQ_INSERT_HEAD(&psm->connections, c, listEntry);
    psm->connectionsSize++;

    /* Validate-connect to check the parameters */
    ret = UA_PubSubConnection_connect(psm, c, true);
    if(ret != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "Could not create the PubSubConnection. "
                     "The connection parameters did not validate.");
        UA_PubSubConnection_delete(psm, c);
        return ret;
    }

    /* Cache the log string */
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "PubSubConnection %N\t| ", c->head.identifier);
    c->head.logIdString = UA_STRING_ALLOC(tmpLogIdStr);

    /* Notify the application that a new Connection was created.
     * This may internally adjust the config */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        UA_StatusCode res = server->config.pubSubConfig.
            componentLifecycleCallback(server, c->head.identifier,
                                       UA_PUBSUBCOMPONENT_CONNECTION, false);
        if(res != UA_STATUSCODE_GOOD) {
            UA_PubSubConnection_delete(psm, c);
            return res;
        }
    }

    UA_LOG_INFO_PUBSUB(psm->logging, c, "Connection created (State: %s)",
                       UA_PubSubState_name(c->head.state));

    /* Copy the created NodeId to the output. Cannot fail as we create a
     * numerical NodeId. */
    if(cId)
        UA_NodeId_copy(&c->head.identifier, cId);

    /* Enable the Connection immediately if the enabled flag is set */
    if(cc->enabled)
        UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_OPERATIONAL);

    return UA_STATUSCODE_GOOD;
}

static void
delayedPubSubConnection_delete(void *application, void *context) {
    UA_PubSubManager *psm = (UA_PubSubManager*)application;
    UA_Server *server = psm->sc.server;
    UA_PubSubConnection *c = (UA_PubSubConnection*)context;
    lockServer(server);
    UA_PubSubConnection_delete(psm, c);
    unlockServer(server);
}

/* Clean up the PubSubConnection. If no EventLoop connection is attached we can
 * immediately free. Otherwise we close the EventLoop connections and free in
 * the connection callback. */
UA_StatusCode
UA_PubSubConnection_delete(UA_PubSubManager *psm, UA_PubSubConnection *c) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Check with the application if we can remove */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        UA_StatusCode res = server->config.pubSubConfig.
            componentLifecycleCallback(server, c->head.identifier,
                                       UA_PUBSUBCOMPONENT_CONNECTION, true);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Disable (and disconnect) and set the deleteFlag. This prevents a
     * reconnect and triggers the deletion when the last open socket is
     * closed. */
    c->deleteFlag = true;
    UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_DISABLED);

    /* Stop and all ReaderGroupds and WriterGroups attached to the Connection.
     * We need to disable all to remove the Connection.*/
    UA_ReaderGroup *rg, *tmpRg;
    LIST_FOREACH(rg, &c->readerGroups, listEntry) {
        UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED);
    }

    UA_WriterGroup *wg, *tmpWg;
    LIST_FOREACH(wg, &c->writerGroups, listEntry) {
        UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_DISABLED);
    }

    /* Remove all ReaderGorups and WriterGroups */
    LIST_FOREACH_SAFE(rg, &c->readerGroups, listEntry, tmpRg) {
        UA_ReaderGroup_remove(psm, rg);
    }

    LIST_FOREACH_SAFE(wg, &c->writerGroups, listEntry, tmpWg) {
        UA_WriterGroup_remove(psm, wg);
    }

    /* Not all sockets are closed. This method will be called again */
    if(c->sendChannel != 0 || c->recvChannelsSize > 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The WriterGroups / ReaderGroups are not deleted. Try again in the next
     * iteration of the event loop.*/
    if(!LIST_EMPTY(&c->writerGroups) || !LIST_EMPTY(&c->readerGroups)) {
        UA_EventLoop *el = psm->sc.server->config.eventLoop;
        c->dc.callback = delayedPubSubConnection_delete;
        c->dc.application = psm;
        c->dc.context = c;
        el->addDelayedCallback(el, &c->dc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Remove from the information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(psm->sc.server, c->head.identifier, true);
#endif

    /* Unlink from the server */
    TAILQ_REMOVE(&psm->connections, c, listEntry);
    psm->connectionsSize--;

    UA_LOG_INFO_PUBSUB(psm->logging, c, "Connection deleted");

    UA_PubSubConnectionConfig_clear(&c->config);
    UA_PubSubComponentHead_clear(&c->head);
    UA_free(c);

    return UA_STATUSCODE_GOOD;
}

static void
UA_PubSubConnection_process(UA_PubSubManager *psm, UA_PubSubConnection *c,
                            const UA_ByteString msg) {
    UA_LOG_TRACE_PUBSUB(psm->logging, c, "Processing a received buffer");

#ifdef UA_DEBUG_DUMP_PKGS
    UA_dump_hex_pkg(msg.data, msg.length);
#endif

    UA_Boolean processed = false;
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));

    /* Decode the NetworkMessage with the first matching ReaderGroup */
    UA_ReaderGroup *rg;
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    LIST_FOREACH(rg, &c->readerGroups, listEntry) {
        if(rg->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
           rg->head.state != UA_PUBSUBSTATE_PREOPERATIONAL)
            continue;
        if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP) {
            res = UA_ReaderGroup_decodeNetworkMessage(psm, rg, msg, &nm);
        } else {
#ifdef UA_ENABLE_JSON_ENCODING
            res = UA_ReaderGroup_decodeNetworkMessageJSON(psm, rg, msg, &nm);
#else
            res = UA_STATUSCODE_BADNOTSUPPORTED;
            UA_LOG_WARNING_PUBSUB(psm->logging, c, "JSON support is not activated");
#endif
        }
        if(res == UA_STATUSCODE_GOOD)
            break;
    }

    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Process the received message for all ReaderGroups */
    LIST_FOREACH(rg, &c->readerGroups, listEntry) {
        if(rg->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
           rg->head.state != UA_PUBSUBSTATE_PREOPERATIONAL)
            continue;
        processed |= UA_ReaderGroup_process(psm, rg, &nm);
    }
    UA_NetworkMessage_clear(&nm);

 finish:
    if(!processed) {
        UA_DateTime nowM = UA_DateTime_nowMonotonic();
        if(c->silenceErrorUntil < nowM) {
            UA_LOG_WARNING_PUBSUB(psm->logging, c,
                                  "Message received that could not be processed "
                                  "with StatusCode %s. Check PublisherId, "
                                  "WriterGroupId and DatasetWriterId",
                                  UA_StatusCode_name(res));
            c->silenceErrorUntil = nowM + (UA_DateTime)(10.0 * UA_DATETIME_SEC);
        }
    }
}

UA_StatusCode
UA_PubSubConnection_setPubSubState(UA_PubSubManager *psm, UA_PubSubConnection *c,
                                   UA_PubSubState targetState) {
    if(c->deleteFlag && targetState != UA_PUBSUBSTATE_DISABLED) {
        UA_LOG_WARNING_PUBSUB(psm->logging, c,
                              "The connection is being deleted. Can only be disabled.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Callback to modify the WriterGroup config and change the targetState
     * before the state machine executes */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.beforeStateChangeCallback) {
        server->config.pubSubConfig.
            beforeStateChangeCallback(server, c->head.identifier, &targetState);
    }

    /* Are we doing a top-level state update or recursively? */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubState oldState = c->head.state;
    UA_Boolean isTransient = c->head.transientState;
    c->head.transientState = true;

    /* Custom state machine */
    if(c->config.customStateMachine) {
        ret = c->config.customStateMachine(server, c->head.identifier, c->config.context,
                                           &c->head.state, targetState);
        goto finalize_state_machine;
    }

    /* Internal state machine */
    switch(targetState) {
        /* Disabled or Error */
        case UA_PUBSUBSTATE_ERROR:
        case UA_PUBSUBSTATE_DISABLED:
            UA_PubSubConnection_disconnect(c);
            c->head.state = targetState;
            break;

        case UA_PUBSUBSTATE_PAUSED:
        case UA_PUBSUBSTATE_PREOPERATIONAL:
        case UA_PUBSUBSTATE_OPERATIONAL:
            /* Cannot go operational if the PubSubManager is not started */
            if(psm->sc.state != UA_LIFECYCLESTATE_STARTED) {
                /* Avoid repeat warnings */
                if(oldState != UA_PUBSUBSTATE_PAUSED) {
                    UA_LOG_WARNING_PUBSUB(psm->logging, c,
                                          "Cannot enable the connection while the "
                                          "server is not running -> Paused State");
                }
                c->head.state = UA_PUBSUBSTATE_PAUSED;
                UA_PubSubConnection_disconnect(c);
                break;
            }

            c->head.state = UA_PUBSUBSTATE_OPERATIONAL;

            /* Whether the connection needs to connect depends on whether a
             * ReaderGroup or WriterGroup is attached. If not, then we don't
             * open any connections. */
            if(UA_PubSubConnection_canConnect(c))
                ret = UA_PubSubConnection_connect(psm, c, false);
            break;

            /* Unknown case */
        default:
            ret = UA_STATUSCODE_BADINTERNALERROR;
            break;
    }

    /* Failure */
    if(ret != UA_STATUSCODE_GOOD) {
        c->head.state = UA_PUBSUBSTATE_ERROR;
        UA_PubSubConnection_disconnect(c);
    }

 finalize_state_machine:

    /* Only the top-level state update (if recursive calls are happening)
     * notifies the application and updates Reader and WriterGroups */
    c->head.transientState = isTransient;
    if(c->head.transientState)
        return ret;

    /* No state change has happened */
    if(c->head.state == oldState)
        return ret;

    UA_LOG_INFO_PUBSUB(psm->logging, c, "%s -> %s",
                       UA_PubSubState_name(oldState),
                       UA_PubSubState_name(c->head.state));

    /* Inform application about state change */
    if(server->config.pubSubConfig.stateChangeCallback) {
        server->config.pubSubConfig.
            stateChangeCallback(server, c->head.identifier, c->head.state, ret);
    }

    /* Children evaluate their state machine after the state change of the parent.
     * Keep the current child state as the target state for the child. */
    UA_ReaderGroup *rg;
    LIST_FOREACH(rg, &c->readerGroups, listEntry) {
        if(psm->pubSubInitialSetupMode && rg->config.enabled) {
            UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_OPERATIONAL);
        } else {
            UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);
        }
    }
    UA_WriterGroup *wg;
    LIST_FOREACH(wg, &c->writerGroups, listEntry) {
        if(psm->pubSubInitialSetupMode && wg->config.enabled) {
            UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_OPERATIONAL);
        } else {
            UA_WriterGroup_setPubSubState(psm, wg, wg->head.state);
        }
    }

    /* Update the PubSubManager state. It will go from STOPPING to STOPPED when
     * the last socket has closed. */
    UA_PubSubManager_setState(psm, psm->sc.state);

    return ret;
}

static UA_StatusCode
enablePubSubConnection(UA_PubSubManager *psm, const UA_NodeId connectionId) {
    UA_PubSubConnection *c = UA_PubSubConnection_find(psm, connectionId);
    return (c) ? UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_OPERATIONAL)
        : UA_STATUSCODE_BADNOTFOUND;
}

static UA_StatusCode
disablePubSubConnection(UA_PubSubManager *psm, const UA_NodeId connectionId) {
    UA_PubSubConnection *c = UA_PubSubConnection_find(psm, connectionId);
    return (c) ? UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_DISABLED)
        : UA_STATUSCODE_BADNOTFOUND;
}

/***********************/
/* Connection Handling */
/***********************/

static UA_StatusCode
UA_PubSubConnection_connectUDP(UA_PubSubManager *psm, UA_PubSubConnection *c,
                               UA_Boolean validate);

static UA_StatusCode
UA_PubSubConnection_connectETH(UA_PubSubManager *psm, UA_PubSubConnection *c,
                               UA_Boolean validate);

typedef struct  {
    UA_String profileURI;
    UA_String protocol;
    UA_Boolean json;
    UA_StatusCode (*connect)(UA_PubSubManager *psm, UA_PubSubConnection *c,
                             UA_Boolean validate);
} ConnectionProfileMapping;

static ConnectionProfileMapping connectionProfiles[UA_PUBSUB_PROFILES_SIZE] = {
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"),
     UA_STRING_STATIC("udp"), false, UA_PubSubConnection_connectUDP},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp"),
     UA_STRING_STATIC("mqtt"), false, NULL},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json"),
     UA_STRING_STATIC("mqtt"), true, NULL},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"),
     UA_STRING_STATIC("eth"), false, UA_PubSubConnection_connectETH}
};

static void
UA_PubSubConnection_detachConnection(UA_PubSubManager *psm,
                                     UA_ConnectionManager *cm,
                                     UA_PubSubConnection *c,
                                     uintptr_t connectionId) {
    if(c->sendChannel == connectionId) {
        UA_LOG_INFO_PUBSUB(psm->logging, c, "Detach send-connection %S %u",
                           cm->protocol, (unsigned)connectionId);
        c->sendChannel = 0;
        return;
    }
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] != connectionId)
            continue;
        UA_LOG_INFO_PUBSUB(psm->logging, c, "Detach receive-connection %S %u",
                           cm->protocol, (unsigned)connectionId);
        c->recvChannels[i] = 0;
        c->recvChannelsSize--;
        return;
    }
}

static UA_StatusCode
UA_PubSubConnection_attachSendConnection(UA_PubSubManager *psm,
                                         UA_ConnectionManager *cm,
                                         UA_PubSubConnection *c,
                                         uintptr_t connectionId) {
    if(c->sendChannel != 0 && c->sendChannel != connectionId)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_LOG_INFO_PUBSUB(psm->logging, c, "Attach send-connection %S %u",
                       cm->protocol, (unsigned)connectionId);
    c->sendChannel = connectionId;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_PubSubConnection_attachRecvConnection(UA_PubSubManager *psm,
                                         UA_ConnectionManager *cm,
                                         UA_PubSubConnection *c,
                                         uintptr_t connectionId) {
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] == connectionId)
            return UA_STATUSCODE_GOOD;
    }
    if(c->recvChannelsSize >= UA_PUBSUB_MAXCHANNELS)
        return UA_STATUSCODE_BADINTERNALERROR;
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] != 0)
            continue;
        UA_LOG_INFO_PUBSUB(psm->logging, c, "Attach receive-connection %S %u",
                           cm->protocol, (unsigned)connectionId);
        c->recvChannels[i] = connectionId;
        c->recvChannelsSize++;
        break;
    }
    return UA_STATUSCODE_GOOD;
}

static void
UA_PubSubConnection_disconnect(UA_PubSubConnection *c) {   
    if(!c->cm)
        return;
    if(c->sendChannel != 0)
        c->cm->closeConnection(c->cm, c->sendChannel);
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] != 0)
            c->cm->closeConnection(c->cm, c->recvChannels[i]);
    }
}

static void
PubSubChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                      void *application, void **connectionContext,
                      UA_ConnectionState state, const UA_KeyValueMap *params,
                      UA_ByteString msg, UA_Boolean recv) {
    if(!connectionContext)
        return;

    /* Get the context pointers */
    UA_PubSubConnection *psc = (UA_PubSubConnection*)*connectionContext;
    UA_PubSubManager *psm = (UA_PubSubManager*)application;
    UA_Server *server = psm->sc.server;

    UA_LOG_TRACE_PUBSUB(psm->logging, psc,
                        "Connection Callback with state %i", state);

    lockServer(server);

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        /* Reset the connection identifiers */
        UA_PubSubConnection_detachConnection(psm, cm, psc, connectionId);

        /* PSC marked for deletion and the last EventLoop connection has closed */
        if(psc->deleteFlag && psc->recvChannelsSize == 0 && psc->sendChannel == 0) {
            UA_PubSubConnection_delete(psm, psc);
            unlockServer(server);
            return;
        }

        /* Reconnect automatically if the connection was operational. This sets
         * the connection state if connecting fails. Attention! If there are
         * several send or recv channels, then the connection is only reopened if
         * all of them close - which is usually the case. */
        if(psc->head.state == UA_PUBSUBSTATE_OPERATIONAL)
            UA_PubSubConnection_connect(psm, psc, false);

        /* Switch the psm state from stopping to stopped once the last
         * connection has closed */
        UA_PubSubManager_setState(psm, psm->sc.state);

        unlockServer(server);
        return;
    }

    /* Store the connectionId (if a new connection) */
    UA_StatusCode res = (recv) ?
        UA_PubSubConnection_attachRecvConnection(psm, cm, psc, connectionId) :
        UA_PubSubConnection_attachSendConnection(psm, cm, psc, connectionId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_PUBSUB(psm->logging, psc,
                              "No more space for an additional EventLoop connection");
        if(psc->cm)
            psc->cm->closeConnection(psc->cm, connectionId);
        unlockServer(server);
        return;
    }

    /* Connection open, set to operational if not already done */
    UA_PubSubConnection_setPubSubState(psm, psc, psc->head.state);

    /* Message received */
    if(UA_LIKELY(recv && msg.length > 0))
        UA_PubSubConnection_process(psm, psc, msg);
    
    unlockServer(server);
}

static void
PubSubRecvChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                         void *application, void **connectionContext,
                         UA_ConnectionState state, const UA_KeyValueMap *params,
                         UA_ByteString msg) {
    PubSubChannelCallback(cm, connectionId, application, connectionContext,
                         state, params, msg, true);
}

static void
PubSubSendChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                         void *application, void **connectionContext,
                         UA_ConnectionState state, const UA_KeyValueMap *params,
                         UA_ByteString msg) {
    PubSubChannelCallback(cm, connectionId, application, connectionContext,
                         state, params, msg, false);
}

static UA_StatusCode
UA_PubSubConnection_connectUDP(UA_PubSubManager *psm, UA_PubSubConnection *c,
                               UA_Boolean validate) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port;
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "Could not parse the UDP network URL");
        return res;
    }

    /* Detect a wildcard address for unicast receiving. The individual
     * DataSetWriters then contain additional target hostnames for sending.
     *
     * "localhost" and the empty hostname are used as a special "receive all"
     * wildcard for PubSub UDP. All other addresses (also the 127.0.0/8 and ::1
     * range) are handled differently. For them we only receive messages that
     * originate from these addresses.
     *
     * The EventLoop backend detects whether an address is multicast capable and
     * registers it for the multicast group in the background. */
    UA_String localhostAddr = UA_STRING_STATIC("localhost");
    UA_Boolean receive_all =
        (address.length == 0) || UA_String_equal(&localhostAddr, &address);

    /* Set up the connection parameters */
    UA_Boolean listen = true;
    UA_Boolean reuse = true;
    UA_Boolean loopback = true;
    UA_KeyValuePair kvp[7];
    UA_KeyValueMap kvm = {5, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[2].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "reuse");
    UA_Variant_setScalar(&kvp[3].value, &reuse, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[4].key = UA_QUALIFIEDNAME(0, "loopback");
    UA_Variant_setScalar(&kvp[4].value, &loopback, &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(!receive_all) {
        /* The "receive all" wildcard is different in the eventloop UDP layer.
         * Omit the address entirely to receive all.*/
        kvp[5].key = UA_QUALIFIEDNAME(0, "address");
        UA_Variant_setScalar(&kvp[5].value, &address, &UA_TYPES[UA_TYPES_STRING]);
        kvm.mapSize++;
    }
    if(!UA_String_isEmpty(&addressUrl->networkInterface)) {
        kvp[kvm.mapSize].key = UA_QUALIFIEDNAME(0, "interface");
        UA_Variant_setScalar(&kvp[kvm.mapSize].value, &addressUrl->networkInterface,
                             &UA_TYPES[UA_TYPES_STRING]);
        kvm.mapSize++;
    }

    /* Open a recv connection */
    if(validate || (c->recvChannelsSize == 0 && c->readerGroupsSize > 0)) {
        res = c->cm->openConnection(c->cm, &kvm, psm, c, PubSubRecvChannelCallback);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_PUBSUB(psm->logging, c,
                                "Could not open an UDP channel for receiving");
            return res;
        }
    }

    /* Receive all -- sending is handled in the DataSetWriter */
    if(receive_all) {
        UA_LOG_INFO_PUBSUB(psm->logging, c,
                           "Localhost address - don't open UDP send connection");
        return UA_STATUSCODE_GOOD;
    }

    /* Open a send connection */
    if(validate || (c->sendChannel == 0 && c->writerGroupsSize > 0)) {
        listen = false;
        res = c->cm->openConnection(c->cm, &kvm, psm, c, PubSubSendChannelCallback);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_PUBSUB(psm->logging, c, "Could not open an UDP recv channel");
            return res;
        }
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_PubSubConnection_connectETH(UA_PubSubManager *psm, UA_PubSubConnection *c,
                               UA_Boolean validate) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Extract hostname and port */
    UA_String address;

    UA_UInt16 vid = 0;
    UA_Byte pcp = 0;

    UA_StatusCode res = UA_parseEndpointUrlEthernet(&addressUrl->url, &address, &vid, &pcp);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "Could not parse the ETH network URL");
        return res;
    }

    UA_Boolean listen = true;
    UA_KeyValuePair kvp[7];
    UA_KeyValueMap kvm = {7, kvp};
    
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "interface");
    UA_Variant_setScalar(&kvp[2].value, &addressUrl->networkInterface,
                         &UA_TYPES[UA_TYPES_STRING]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[3].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);
    UA_UInt16 ether_type = 0xB62C;
    kvp[4].key = UA_QUALIFIEDNAME(0, "ethertype");
    UA_Variant_setScalar(&kvp[4].value, &ether_type, &UA_TYPES[UA_TYPES_UINT16]);
    
    kvp[5].key = UA_QUALIFIEDNAME(0,"vid");
    UA_Variant_setScalar(&kvp[5].value, &vid, &UA_TYPES[UA_TYPES_UINT16]);

    kvp[6].key = UA_QUALIFIEDNAME(0,"pcp");
    UA_Variant_setScalar(&kvp[6].value, &pcp, &UA_TYPES[UA_TYPES_BYTE]);

    /* Open recv channels */
    if(validate || (c->recvChannelsSize == 0 && c->readerGroupsSize > 0)) {
        res = c->cm->openConnection(c->cm, &kvm, psm, c, PubSubRecvChannelCallback);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_PUBSUB(psm->logging, c, "Could not open an ETH recv channel");
            return res;
        }
    }

    /* Open send channels */
    if(validate || (c->sendChannel == 0 && c->writerGroupsSize > 0)) {
        listen = false;
        res = c->cm->openConnection(c->cm, &kvm, psm, c, PubSubSendChannelCallback);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_PUBSUB(psm->logging, c,
                                "Could not open an ETH channel for sending");
        }
    }

    return res;
}

static UA_Boolean
UA_PubSubConnection_canConnect(UA_PubSubConnection *c) {
    if(c->sendChannel == 0 && c->writerGroupsSize > 0)
        return true;
    if(c->recvChannelsSize == 0 && c->readerGroupsSize > 0)
        return true;
    return false;
}

static UA_StatusCode
UA_PubSubConnection_connect(UA_PubSubManager *psm, UA_PubSubConnection *c,
                            UA_Boolean validate) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    if(!el) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "No EventLoop configured");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Look up the connection manager for the connection */
    ConnectionProfileMapping *profile = NULL;
    for(size_t i = 0; i < UA_PUBSUB_PROFILES_SIZE; i++) {
        if(!UA_String_equal(&c->config.transportProfileUri,
                            &connectionProfiles[i].profileURI))
            continue;
        profile = &connectionProfiles[i];
        break;
    }

    UA_ConnectionManager *cm = (profile) ? getCM(el, profile->protocol) : NULL;
    if(!cm || (c->cm && cm != c->cm)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c,
                            "The requested profile \"%S\"is not supported",
                            c->config.transportProfileUri);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the configuration address type */
    if(!UA_Variant_hasScalarType(&c->config.address,
                                 &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE])) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "No NetworkAddressUrlDataType "
                            "for the address configuration");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Update the connection settings from the profile information */
    c->cm = cm;
    c->json = profile->json;

    /* Some protocols (such as MQTT) don't connect at this level */
    return (profile->connect) ?
        profile->connect(psm, c, validate) : UA_STATUSCODE_GOOD;
}

/**************/
/* Server API */
/**************/

UA_StatusCode
UA_Server_getPubSubConnectionConfig(UA_Server *server, const UA_NodeId connection,
                                    UA_PubSubConnectionConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubConnection *c = UA_PubSubConnection_find(getPSM(server), connection);
    UA_StatusCode res = (c) ?
        UA_PubSubConnectionConfig_copy(&c->config, config) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_addPubSubConnection(UA_Server *server,
                              const UA_PubSubConnectionConfig *cc,
                              UA_NodeId *cId) {
    if(!server || !cc)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode res = (psm) ?
        UA_PubSubConnection_create(psm, cc, cId) : UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId cId) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_PubSubConnection *c = UA_PubSubConnection_find(psm, cId);
    if(!c) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_DISABLED);
    UA_PubSubConnection_delete(psm, c);
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_enablePubSubConnection(UA_Server *server, const UA_NodeId cId) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode res = (psm) ?
        enablePubSubConnection(psm, cId) : UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_disablePubSubConnection(UA_Server *server, const UA_NodeId cId) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode res = (psm) ?
        disablePubSubConnection(psm, cId) : UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_processPubSubConnectionReceive(UA_Server *server,
                                         const UA_NodeId connectionId,
                                         const UA_ByteString packet) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;
    lockServer(server);
    UA_StatusCode res = UA_STATUSCODE_BADINTERNALERROR;
    UA_PubSubManager *psm = getPSM(server);
    if(psm) {
        UA_PubSubConnection *c = UA_PubSubConnection_find(psm, connectionId);
        if(c) {
            res = UA_STATUSCODE_GOOD;
            UA_PubSubConnection_process(psm, c, packet);
        } else {
            res = UA_STATUSCODE_BADNOTFOUND;
        }
    }
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_updatePubSubConnectionConfig(UA_Server *server,
                                       const UA_NodeId connectionId,
                                       const UA_PubSubConnectionConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);

    /* Find the connection */
    UA_PubSubManager *psm = getPSM(server);
    UA_PubSubConnection *c = UA_PubSubConnection_find(psm, connectionId);
    if(!c) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Verify the connection is disabled */
    if(UA_PubSubState_isEnabled(c->head.state)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c,
                            "The PubSubConnection must be disabled to update the config");
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Store the old config */
    UA_PubSubConnectionConfig oldConfig = c->config;
    memset(&c->config, 0, sizeof(UA_PubSubConnectionConfig));

    /* Copy the connection config */
    UA_StatusCode res = UA_PubSubConnectionConfig_copy(config, &c->config);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Validate-connect to check the parameters */
    res = UA_PubSubConnection_connect(psm, c, true);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "The connection parameters did not validate");
        goto errout;
    }

    UA_PubSubConnectionConfig_clear(&oldConfig);
    unlockServer(server);
    return UA_STATUSCODE_GOOD;

 errout:
    /* Restore the old config */
    UA_PubSubConnectionConfig_clear(&c->config);
    c->config = oldConfig;
    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_dataset.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019-2021 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

static void
UA_DataSetField_clear(UA_DataSetField *field) {
    UA_DataSetFieldConfig_clear(&field->config);
    UA_NodeId_clear(&field->identifier);
    UA_NodeId_clear(&field->publishedDataSet);
    UA_FieldMetaData_clear(&field->fieldMetaData);
}

UA_StatusCode
UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src,
                               UA_PublishedDataSetConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_PublishedDataSetConfig));
    res |= UA_String_copy(&src->name, &dst->name);
    switch(src->publishedDataSetType) {
        case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
            //no additional items
            break;

        case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
            if(src->config.itemsTemplate.variablesToAddSize > 0) {
                dst->config.itemsTemplate.variablesToAdd = (UA_PublishedVariableDataType *)
                    UA_calloc(src->config.itemsTemplate.variablesToAddSize,
                              sizeof(UA_PublishedVariableDataType));
                if(!dst->config.itemsTemplate.variablesToAdd) {
                    res = UA_STATUSCODE_BADOUTOFMEMORY;
                    break;
                }
                dst->config.itemsTemplate.variablesToAddSize =
                    src->config.itemsTemplate.variablesToAddSize;
            }

            for(size_t i = 0; i < src->config.itemsTemplate.variablesToAddSize; i++) {
                res |= UA_PublishedVariableDataType_copy(&src->config.itemsTemplate.variablesToAdd[i],
                                                         &dst->config.itemsTemplate.variablesToAdd[i]);
            }
            res |= UA_DataSetMetaDataType_copy(&src->config.itemsTemplate.metaData,
                                               &dst->config.itemsTemplate.metaData);
            break;

        default:
            res = UA_STATUSCODE_BADINVALIDARGUMENT;
            break;
    }

    if(res != UA_STATUSCODE_GOOD)
        UA_PublishedDataSetConfig_clear(dst);
    return res;
}

UA_PublishedDataSet *
UA_PublishedDataSet_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_PublishedDataSet *tmpPDS = NULL;
    TAILQ_FOREACH(tmpPDS, &psm->publishedDataSets, listEntry) {
        if(UA_NodeId_equal(&id, &tmpPDS->head.identifier))
            break;
    }
    return tmpPDS;
}

UA_PublishedDataSet *
UA_PublishedDataSet_findByName(UA_PubSubManager *psm, const UA_String name) {
    if(!psm)
        return NULL;
    UA_PublishedDataSet *tmpPDS = NULL;
    TAILQ_FOREACH(tmpPDS, &psm->publishedDataSets, listEntry) {
        if(UA_String_equal(&name, &tmpPDS->config.name))
            break;
    }
    return tmpPDS;
}

void
UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig *pdsConfig) {
    //delete pds config
    UA_String_clear(&pdsConfig->name);
    switch (pdsConfig->publishedDataSetType){
        case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
            //no additional items
            break;
        case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
            if(pdsConfig->config.itemsTemplate.variablesToAddSize > 0){
                for(size_t i = 0; i < pdsConfig->config.itemsTemplate.variablesToAddSize; i++){
                    UA_PublishedVariableDataType_clear(&pdsConfig->config.itemsTemplate.variablesToAdd[i]);
                }
                UA_free(pdsConfig->config.itemsTemplate.variablesToAdd);
            }
            UA_DataSetMetaDataType_clear(&pdsConfig->config.itemsTemplate.metaData);
            break;
        default:
            break;
    }
}

/* The fieldMetaData variable has to be cleaned up external in case of an error */
static UA_StatusCode
generateFieldMetaData(UA_PubSubManager *psm, UA_PublishedDataSet *pds,
                      UA_DataSetField *field) {
    if(field->config.dataSetFieldType != UA_PUBSUB_DATASETFIELD_VARIABLE)
        return UA_STATUSCODE_BADNOTSUPPORTED;

    UA_FieldMetaData *fmd = &field->fieldMetaData;
    const UA_DataSetVariableConfig *var = &field->config.field.variable;

    /* Name */
    UA_StatusCode res = UA_String_copy(&var->fieldNameAlias, &fmd->name);
    UA_CHECK_STATUS(res, return res);

    /* Description */
    res = UA_LocalizedText_copy(&var->description, &fmd->description);
    UA_CHECK_STATUS(res, return res);

    /* FieldFlags */
    if(var->promotedField)
        fmd->fieldFlags = UA_DATASETFIELDFLAGS_PROMOTEDFIELD;
    else
        fmd->fieldFlags = UA_DATASETFIELDFLAGS_NONE;

    /* DataType */
    res = readWithReadValue(psm->sc.server, &var->publishParameters.publishedVariable,
                            UA_ATTRIBUTEID_DATATYPE, &fmd->dataType);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, pds,
                            "PubSub meta data generation: Reading the DataType failed");
        return res;
    }

    /* BuiltinType */
    const UA_DataType *type =
        UA_findDataTypeWithCustom(&fmd->dataType,
                                  psm->sc.server->config.customDataTypes);
    if(!type) {
        /* (1) Abstract types always have the built-in type Variant since they
         * can result in different concrete types in a DataSetMessage. */
        fmd->builtInType = UA_DATATYPEKIND_VARIANT;
    } else if(type->typeKind == UA_DATATYPEKIND_ENUM) {
        /* (2) Enumeration DataTypes are encoded as Int32. */
        fmd->builtInType = UA_DATATYPEKIND_INT32;
    } else if(type->typeKind == UA_DATATYPEKIND_STRUCTURE ||
              type->typeKind == UA_DATATYPEKIND_OPTSTRUCT ||
              type->typeKind == UA_DATATYPEKIND_UNION) {
        /* (3) Structure and Union DataTypes are encoded as ExtensionObject. */
        fmd->builtInType = UA_DATATYPEKIND_EXTENSIONOBJECT;
    } else if(type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO) {
        /* (4) DataTypes derived from built-in types have the BuiltInType of the
         * corresponding base DataType. */
        fmd->builtInType = type->typeKind;
    } else {
        /* (5) OptionSet DataTypes are either encoded as one of the concrete
           UInteger DataTypes or as an instance of an OptionSetType in an
           ExtensionObject. */
        fmd->builtInType = UA_DATATYPEKIND_EXTENSIONOBJECT;
    }

    fmd->builtInType++; /* Go from UA_DataTypeKind to the builtin type index from Part 6 */

    /* ValueRank */
    res = readWithReadValue(psm->sc.server, &var->publishParameters.publishedVariable,
                            UA_ATTRIBUTEID_VALUERANK, &fmd->valueRank);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, pds,
                            "PubSub meta data generation: Reading the ValueRank failed");
        return res;
    }

    /* ArrayDimensions */
    UA_Variant value;
    UA_Variant_init(&value);
    res = readWithReadValue(psm->sc.server, &var->publishParameters.publishedVariable,
                            UA_ATTRIBUTEID_ARRAYDIMENSIONS, &value);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, pds,
                            "PubSub meta data generation: Reading the ArrayDimensions failed");
        return res;
    }
    fmd->arrayDimensions = (UA_UInt32*)value.data;
    fmd->arrayDimensionsSize = value.arrayLength;
    value.data = NULL;
    value.arrayLength = 0;
    UA_Variant_clear(&value);

    /* MaxStringLength */
    if(field->config.field.variable.maxStringLength > 0) {
        if(fmd->builtInType - 1 == UA_DATATYPEKIND_BYTESTRING ||
           fmd->builtInType - 1 == UA_DATATYPEKIND_STRING) {
            fmd->maxStringLength = field->config.field.variable.maxStringLength;
        } else {
            UA_LOG_ERROR_PUBSUB(psm->logging, pds,
                                "PubSub meta data generation: MaxStringLength with "
                                "incompatible DataType configured");
        }
    }

    /* DataSetFieldId */
    if(!UA_Guid_equal(&var->dataSetFieldId, &UA_GUID_NULL)) {
        fmd->dataSetFieldId = var->dataSetFieldId;
    } else {
        fmd->dataSetFieldId = UA_PubSubManager_generateUniqueGuid(psm);
    }

    /* Properties */
    fmd->properties = NULL;
    fmd->propertiesSize = 0;

    return UA_STATUSCODE_GOOD;
}

UA_DataSetFieldResult
UA_DataSetField_create(UA_PubSubManager *psm, const UA_NodeId publishedDataSet,
                       const UA_DataSetFieldConfig *fieldConfig,
                       UA_NodeId *fieldIdentifier) {
    UA_DataSetFieldResult result;
    memset(&result, 0, sizeof(UA_DataSetFieldResult));
    if(!fieldConfig) {
        result.result = UA_STATUSCODE_BADINVALIDARGUMENT;
        return result;
    }

    UA_PublishedDataSet *currDS =
        UA_PublishedDataSet_find(psm, publishedDataSet);
    if(!currDS) {
        result.result = UA_STATUSCODE_BADNOTFOUND;
        return result;
    }

    /* If currDS was found, psm != NULL */
    if(currDS->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_PUBSUB(psm->logging, currDS,
                              "Adding DataSetField failed: PublishedDataSet already in use");
        result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
        return result;
    }

    if(currDS->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS) {
        result.result = UA_STATUSCODE_BADNOTIMPLEMENTED;
        return result;
    }

    UA_DataSetField *newField = (UA_DataSetField*)UA_calloc(1, sizeof(UA_DataSetField));
    if(!newField) {
        result.result = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    result.result = UA_DataSetFieldConfig_copy(fieldConfig, &newField->config);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_free(newField);
        return result;
    }

    result.result = UA_NodeId_copy(&currDS->head.identifier, &newField->publishedDataSet);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_DataSetField_clear(newField);
        UA_free(newField);
        return result;
    }

    /* Initialize the field metadata. Also generates a FieldId, if not given in config */
    result.result = generateFieldMetaData(psm, currDS, newField);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_DataSetField_clear(newField);
        UA_free(newField);
        return result;
    }

    /* Append to the metadata fields array. Point of last return. */
    result.result = UA_Array_appendCopy((void**)&currDS->dataSetMetaData.fields,
                                        &currDS->dataSetMetaData.fieldsSize,
                                        &newField->fieldMetaData,
                                        &UA_TYPES[UA_TYPES_FIELDMETADATA]);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_DataSetField_clear(newField);
        UA_free(newField);
        return result;
    }

    /* Copy the identifier from the metadata. Cannot fail with a guid NodeId. */
    newField->identifier = UA_NODEID_GUID(1, newField->fieldMetaData.dataSetFieldId);
    if(fieldIdentifier)
        UA_NodeId_copy(&newField->identifier, fieldIdentifier);

    /* Register the field. The order of DataSetFields should be the same in both
     * creating and publishing. So adding DataSetFields at the the end of the
     * DataSets using the TAILQ structure. */
    TAILQ_INSERT_TAIL(&currDS->fields, newField, listEntry);
    currDS->fieldSize++;

    if(newField->config.field.variable.promotedField)
        currDS->promotedFieldsCount++;

    /* Update major version of parent published data set */
    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    currDS->dataSetMetaData.configurationVersion.majorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));

    result.configurationVersion.majorVersion =
        currDS->dataSetMetaData.configurationVersion.majorVersion;
    result.configurationVersion.minorVersion =
        currDS->dataSetMetaData.configurationVersion.minorVersion;

    return result;
}

UA_DataSetFieldResult
UA_DataSetField_remove(UA_PubSubManager *psm, UA_DataSetField *currentField) {
    UA_DataSetFieldResult result;
    memset(&result, 0, sizeof(UA_DataSetFieldResult));

    if(!currentField) {
        result.result = UA_STATUSCODE_BADNOTFOUND;
        return result;
    }

    UA_PublishedDataSet *pds =
        UA_PublishedDataSet_find(psm, currentField->publishedDataSet);
    if(!pds) {
        result.result = UA_STATUSCODE_BADNOTFOUND;
        return result;
    }

    if(pds->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_PUBSUB(psm->logging, pds,
                              "Remove DataSetField failed: PublishedDataSet is in use");
        result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
        return result;
    }

    /* Reduce the counters before the config is cleaned up */
    if(currentField->config.field.variable.promotedField)
        pds->promotedFieldsCount--;

    /* Remove field from DataSetMetaData */
    pds->dataSetMetaData.fieldsSize--;
    if(pds->dataSetMetaData.fieldsSize == 0) {
        UA_FieldMetaData_delete(pds->dataSetMetaData.fields);
        pds->dataSetMetaData.fields = NULL;
    } else {
        /* Clear entry and move later fields to fill the gap */
        size_t i = 0;
        for(; i < pds->dataSetMetaData.fieldsSize + 1; i++) {
            if(UA_Guid_equal(&currentField->fieldMetaData.dataSetFieldId,
                             &pds->dataSetMetaData.fields[i].dataSetFieldId))
                break;
        }
        UA_FieldMetaData_clear(&pds->dataSetMetaData.fields[i]);
        for(; i < pds->dataSetMetaData.fieldsSize; i++) {
            pds->dataSetMetaData.fields[i] = pds->dataSetMetaData.fields[i+1];
        }
    }

    /* Remove */
    pds->fieldSize--;
    TAILQ_REMOVE(&pds->fields, currentField, listEntry);
    UA_DataSetField_clear(currentField);
    UA_free(currentField);

    /* Update major version of PublishedDataSet */
    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    pds->dataSetMetaData.configurationVersion.majorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));

    result.configurationVersion.majorVersion =
        pds->dataSetMetaData.configurationVersion.majorVersion;
    result.configurationVersion.minorVersion =
        pds->dataSetMetaData.configurationVersion.minorVersion;

    return result;
}

UA_StatusCode
UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src,
                           UA_DataSetFieldConfig *dst) {
    if(src->dataSetFieldType != UA_PUBSUB_DATASETFIELD_VARIABLE)
        return UA_STATUSCODE_BADNOTSUPPORTED;
    memcpy(dst, src, sizeof(UA_DataSetFieldConfig));
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_String_copy(&src->field.variable.fieldNameAlias,
                          &dst->field.variable.fieldNameAlias);
    res |= UA_PublishedVariableDataType_copy(&src->field.variable.publishParameters,
                                             &dst->field.variable.publishParameters);
    res |= UA_LocalizedText_copy(&src->field.variable.description,
                                   &dst->field.variable.description);
    if(res != UA_STATUSCODE_GOOD)
        UA_DataSetFieldConfig_clear(dst);
    return res;
}

UA_DataSetField *
UA_DataSetField_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_PublishedDataSet *tmpPDS;
    TAILQ_FOREACH(tmpPDS, &psm->publishedDataSets, listEntry) {
        UA_DataSetField *tmpField;
        TAILQ_FOREACH(tmpField, &tmpPDS->fields, listEntry) {
            if(UA_NodeId_equal(&id, &tmpField->identifier))
                return tmpField;
        }
    }
    return NULL;
}

void
UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig) {
    if(dataSetFieldConfig->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE) {
        UA_String_clear(&dataSetFieldConfig->field.variable.fieldNameAlias);
        UA_PublishedVariableDataType_clear(&dataSetFieldConfig->field.variable.publishParameters);
        UA_LocalizedText_clear(&dataSetFieldConfig->field.variable.description);
    }
}

/* Obtain the latest value for a specific DataSetField. This method is currently
 * called inside the DataSetMessage generation process. */
void
UA_PubSubDataSetField_sampleValue(UA_PubSubManager *psm, UA_DataSetField *field,
                                  UA_DataValue *value) {
    UA_PublishedVariableDataType *params = &field->config.field.variable.publishParameters;

    UA_ReadValueId rvid;
    UA_ReadValueId_init(&rvid);
    rvid.nodeId = params->publishedVariable;
    rvid.attributeId = params->attributeId;
    rvid.indexRange = params->indexRange;
    *value = readWithSession(psm->sc.server, &psm->sc.server->adminSession,
                             &rvid, UA_TIMESTAMPSTORETURN_BOTH);
}

UA_AddPublishedDataSetResult
UA_PublishedDataSet_create(UA_PubSubManager *psm,
                           const UA_PublishedDataSetConfig *publishedDataSetConfig,
                           UA_NodeId *pdsIdentifier) {
    UA_AddPublishedDataSetResult result = {UA_STATUSCODE_BADINVALIDARGUMENT, 0, NULL, {0, 0}};
    if(!psm) {
        result.addResult = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    if(!publishedDataSetConfig) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PublishedDataSet creation failed. No config passed in.");
        return result;
    }

    if(publishedDataSetConfig->publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS){
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PublishedDataSet creation failed. Unsupported PublishedDataSet type.");
        return result;
    }

    if(UA_String_isEmpty(&publishedDataSetConfig->name)) {
        // DataSet has to have a valid name
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PublishedDataSet creation failed. Invalid name.");
        return result;
    }

    if(UA_PublishedDataSet_findByName(psm, publishedDataSetConfig->name)) {
        // DataSet name has to be unique in the publisher
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PublishedDataSet creation failed. DataSet with the same name already exists.");
        result.addResult = UA_STATUSCODE_BADBROWSENAMEDUPLICATED;
        return result;
    }

    /* Create new PDS and add to UA_PubSubManager */
    UA_PublishedDataSet *newPDS = (UA_PublishedDataSet *)
        UA_calloc(1, sizeof(UA_PublishedDataSet));
    if(!newPDS) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PublishedDataSet creation failed. Out of Memory.");
        result.addResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    TAILQ_INIT(&newPDS->fields);

    newPDS->head.componentType = UA_PUBSUBCOMPONENT_PUBLISHEDDATASET;

    UA_PublishedDataSetConfig *newConfig = &newPDS->config;

    /* Deep copy the given connection config */
    UA_StatusCode res = UA_PublishedDataSetConfig_copy(publishedDataSetConfig, newConfig);
    if(res != UA_STATUSCODE_GOOD){
        UA_free(newPDS);
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PublishedDataSet creation failed. Configuration copy failed.");
        result.addResult = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    /* TODO: Parse template config and add fields (later PubSub batch) */
    if(newConfig->publishedDataSetType == UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE) {
    }

    /* Fill the DataSetMetaData */
    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    result.configurationVersion.majorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
    result.configurationVersion.minorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
    switch(newConfig->publishedDataSetType) {
    case UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE:
    case UA_PUBSUB_DATASET_PUBLISHEDEVENTS:
        res = UA_STATUSCODE_BADNOTSUPPORTED;
        break;
    case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
        newPDS->dataSetMetaData.configurationVersion.majorVersion =
            UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
        newPDS->dataSetMetaData.configurationVersion.minorVersion =
            UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
        newPDS->dataSetMetaData.description = UA_LOCALIZEDTEXT_ALLOC("", "");
        newPDS->dataSetMetaData.dataSetClassId = UA_GUID_NULL;
        res = UA_String_copy(&newConfig->name, &newPDS->dataSetMetaData.name);
        break;
    case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
        res = UA_DataSetMetaDataType_copy(&newConfig->config.itemsTemplate.metaData,
                                          &newPDS->dataSetMetaData);
        break;
    default:
        res = UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Abort? */
    result.addResult = res;
    if(result.addResult != UA_STATUSCODE_GOOD) {
        UA_PublishedDataSetConfig_clear(newConfig);
        UA_free(newPDS);
        return result;
    }

    /* Insert into the queue of the manager */
    TAILQ_INSERT_TAIL(&psm->publishedDataSets, newPDS, listEntry);
    psm->publishedDataSetsSize++;

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    /* Create representation and unique id */
    addPublishedDataItemsRepresentation(psm->sc.server, newPDS);
#else
    /* Generate unique nodeId */
    UA_PubSubManager_generateUniqueNodeId(psm, &newPDS->head.identifier);
#endif

    /* Cache the log string */
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "PublishedDataset %N\t| ", newPDS->head.identifier);
    newPDS->head.logIdString = UA_STRING_ALLOC(tmpLogIdStr);

    UA_LOG_INFO_PUBSUB(psm->logging, newPDS, "DataSet created");

    /* Return the created identifier */
    if(pdsIdentifier)
        UA_NodeId_copy(&newPDS->head.identifier, pdsIdentifier);
    return result;
}

UA_StatusCode
UA_PublishedDataSet_remove(UA_PubSubManager *psm, UA_PublishedDataSet *pds) {
    if(pds->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_PUBSUB(psm->logging, pds,
                              "Cannot remove PublishedDataSet failed while in use");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* Search for referenced writers -> delete this writers. (Standard: writer
     * must be connected with PDS) */
    UA_PubSubConnection *conn;
    TAILQ_FOREACH(conn, &psm->connections, listEntry) {
        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &conn->writerGroups, listEntry) {
            UA_DataSetWriter *dsw, *tmpWriter;
            LIST_FOREACH_SAFE(dsw, &wg->writers, listEntry, tmpWriter) {
                if(dsw->connectedDataSet == pds)
                    UA_DataSetWriter_remove(psm, dsw);
            }
        }
    }

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(psm->sc.server, pds->head.identifier, true);
#endif

    UA_LOG_INFO_PUBSUB(psm->logging, pds, "PublishedDataSet deleted");

    /* Unlink from the server */
    TAILQ_REMOVE(&psm->publishedDataSets, pds, listEntry);
    psm->publishedDataSetsSize--;

    /* Clean up the PublishedDataSet */
    UA_DataSetField *field, *tmpField;
    TAILQ_FOREACH_SAFE(field, &pds->fields, listEntry, tmpField) {
        UA_DataSetField_clear(field);
        TAILQ_REMOVE(&pds->fields, field, listEntry);
        UA_free(field);
    }
    UA_PublishedDataSetConfig_clear(&pds->config);
    UA_DataSetMetaDataType_clear(&pds->dataSetMetaData);
    UA_PubSubComponentHead_clear(&pds->head);
    UA_free(pds);

    return UA_STATUSCODE_GOOD;
}

UA_SubscribedDataSet *
UA_SubscribedDataSet_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_SubscribedDataSet *sds;
    TAILQ_FOREACH(sds, &psm->subscribedDataSets, listEntry) {
        if(UA_NodeId_equal(&id, &sds->head.identifier))
            return sds;
    }
    return NULL;
}

UA_SubscribedDataSet *
UA_SubscribedDataSet_findByName(UA_PubSubManager *psm, const UA_String name) {
    if(!psm)
        return NULL;
    UA_SubscribedDataSet *sds;
    TAILQ_FOREACH(sds, &psm->subscribedDataSets, listEntry) {
        if(UA_String_equal(&name, &sds->config.name))
            return sds;
    }
    return NULL;
}

UA_StatusCode
UA_SubscribedDataSetConfig_copy(const UA_SubscribedDataSetConfig *src,
                                UA_SubscribedDataSetConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_SubscribedDataSetConfig));
    res = UA_DataSetMetaDataType_copy(&src->dataSetMetaData, &dst->dataSetMetaData);
    res |= UA_String_copy(&src->name, &dst->name);
    if(src->subscribedDataSetType == UA_PUBSUB_SDS_TARGET) {
        res |= UA_TargetVariablesDataType_copy(&src->subscribedDataSet.target,
                                               &dst->subscribedDataSet.target);
    }
    if(res != UA_STATUSCODE_GOOD)
        UA_SubscribedDataSetConfig_clear(dst);
    return res;
}

void
UA_SubscribedDataSetConfig_clear(UA_SubscribedDataSetConfig *sdsConfig) {
    UA_String_clear(&sdsConfig->name);
    UA_DataSetMetaDataType_clear(&sdsConfig->dataSetMetaData);
    UA_TargetVariablesDataType_clear(&sdsConfig->subscribedDataSet.target);
}

static UA_StatusCode
addSubscribedDataSet(UA_PubSubManager *psm,
                     const UA_SubscribedDataSetConfig *sdsConfig,
                     UA_NodeId *sdsIdentifier) {
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    if(!sdsConfig) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "SubscribedDataSet creation failed. No config passed in.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_SubscribedDataSetConfig tmpSubscribedDataSetConfig;
    memset(&tmpSubscribedDataSetConfig, 0, sizeof(UA_SubscribedDataSetConfig));
    UA_StatusCode res = UA_SubscribedDataSetConfig_copy(sdsConfig,
                                                        &tmpSubscribedDataSetConfig);
    if(res != UA_STATUSCODE_GOOD){
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "SubscribedDataSet creation failed. Configuration copy failed.");
        return res;
    }

    /* Create new PDS and add to UA_PubSubManager */
    UA_SubscribedDataSet *newSubscribedDataSet = (UA_SubscribedDataSet *)
            UA_calloc(1, sizeof(UA_SubscribedDataSet));
    if(!newSubscribedDataSet) {
        UA_SubscribedDataSetConfig_clear(&tmpSubscribedDataSetConfig);
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "SubscribedDataSet creation failed. Out of Memory.");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    newSubscribedDataSet->head.componentType = UA_PUBSUBCOMPONENT_SUBSCRIBEDDDATASET;
    newSubscribedDataSet->config = tmpSubscribedDataSetConfig;
    newSubscribedDataSet->connectedReader = NULL;

    TAILQ_INSERT_TAIL(&psm->subscribedDataSets, newSubscribedDataSet, listEntry);
    psm->subscribedDataSetsSize++;

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    addSubscribedDataSetRepresentation(psm->sc.server, newSubscribedDataSet);
#else
    UA_PubSubManager_generateUniqueNodeId(psm, &newSubscribedDataSet->head.identifier);
#endif

    if(sdsIdentifier)
        UA_NodeId_copy(&newSubscribedDataSet->head.identifier, sdsIdentifier);

    return UA_STATUSCODE_GOOD;
}

void
UA_SubscribedDataSet_remove(UA_PubSubManager *psm, UA_SubscribedDataSet *sds) {
    /* Search for referenced readers */
    UA_PubSubConnection *conn;
    TAILQ_FOREACH(conn, &psm->connections, listEntry) {
        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &conn->readerGroups, listEntry) {
            UA_DataSetReader *dsr, *tmpReader;
            LIST_FOREACH_SAFE(dsr, &rg->readers, listEntry, tmpReader) {
                /* TODO: What if the reader is still operational?
                 * This should be checked before calling _remove. */
                if(dsr == sds->connectedReader)
                    UA_DataSetReader_remove(psm, dsr);
            }
        }
    }

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(psm->sc.server, sds->head.identifier, true);
#endif

    /* Unlink from the server */
    TAILQ_REMOVE(&psm->subscribedDataSets, sds, listEntry);
    psm->subscribedDataSetsSize--;

    /* Clean up */
    UA_SubscribedDataSetConfig_clear(&sds->config);
    UA_PubSubComponentHead_clear(&sds->head);
    UA_free(sds);
}

/**************/
/* Server API */
/**************/

UA_StatusCode
UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pdsId,
                                    UA_PublishedDataSetConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PublishedDataSet *pds = UA_PublishedDataSet_find(getPSM(server), pdsId);
    UA_StatusCode res = (pds) ?
        UA_PublishedDataSetConfig_copy(&pds->config, config) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pdsId,
                                      UA_DataSetMetaDataType *metaData) {
    if(!server || !metaData)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PublishedDataSet *pds = UA_PublishedDataSet_find(getPSM(server), pdsId);
    UA_StatusCode res = (pds) ?
        UA_DataSetMetaDataType_copy(&pds->dataSetMetaData, metaData) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_DataSetFieldResult
UA_Server_addDataSetField(UA_Server *server, const UA_NodeId publishedDataSet,
                          const UA_DataSetFieldConfig *fieldConfig,
                          UA_NodeId *fieldIdentifier) {
    UA_DataSetFieldResult res;
    if(!server || !fieldConfig) {
        memset(&res, 0, sizeof(UA_DataSetFieldResult));
        res.result = UA_STATUSCODE_BADINVALIDARGUMENT;
        return res;
    }
    lockServer(server);
    res = UA_DataSetField_create(getPSM(server), publishedDataSet, fieldConfig, fieldIdentifier);
    unlockServer(server);
    return res;
}

UA_DataSetFieldResult
UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf) {
    UA_DataSetFieldResult res;
    if(!server) {
        memset(&res, 0, sizeof(UA_DataSetFieldResult));
        res.result = UA_STATUSCODE_BADINVALIDARGUMENT;
        return res;
    }
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetField *field = UA_DataSetField_find(psm, dsf);
    res = UA_DataSetField_remove(psm, field);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsfId,
                                UA_DataSetFieldConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_DataSetField *dsf = UA_DataSetField_find(getPSM(server), dsfId);
    UA_StatusCode res = (dsf) ?
        UA_DataSetFieldConfig_copy(&dsf->config, config) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_AddPublishedDataSetResult
UA_Server_addPublishedDataSet(UA_Server *server,
                              const UA_PublishedDataSetConfig *publishedDataSetConfig,
                              UA_NodeId *pdsIdentifier) {
    UA_AddPublishedDataSetResult res;
    if(!server || !publishedDataSetConfig) {
        memset(&res, 0, sizeof(UA_AddPublishedDataSetResult));
        res.addResult = UA_STATUSCODE_BADINTERNALERROR;
        return res;
    }
    lockServer(server);
    res = UA_PublishedDataSet_create(getPSM(server), publishedDataSetConfig, pdsIdentifier);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removePublishedDataSet(UA_Server *server, const UA_NodeId pdsId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_PublishedDataSet *pds = UA_PublishedDataSet_find(psm, pdsId);
    UA_StatusCode res = (pds) ?
        UA_PublishedDataSet_remove(psm, pds) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_addSubscribedDataSet(UA_Server *server,
                               const UA_SubscribedDataSetConfig *sdsConfig,
                               UA_NodeId *sdsIdentifier) {
    if(!server || !sdsConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode res = addSubscribedDataSet(getPSM(server), sdsConfig, sdsIdentifier);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removeSubscribedDataSet(UA_Server *server, const UA_NodeId sdsId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_SubscribedDataSet *sds = UA_SubscribedDataSet_find(psm, sdsId);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(sds) {
        UA_SubscribedDataSet_remove(psm, sds);
        res = UA_STATUSCODE_GOOD;
    }
    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_writer.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019-2021 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */


UA_StatusCode
UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src,
                            UA_DataSetWriterConfig *dst){
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_DataSetWriterConfig));
    retVal |= UA_String_copy(&src->name, &dst->name);
    retVal |= UA_String_copy(&src->dataSetName, &dst->dataSetName);
    retVal |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
    retVal |= UA_KeyValueMap_copy(&src->dataSetWriterProperties, &dst->dataSetWriterProperties);
    if(retVal != UA_STATUSCODE_GOOD)
        UA_DataSetWriterConfig_clear(dst);
    return retVal;
}

UA_DataSetWriter *
UA_DataSetWriter_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            UA_DataSetWriter *dsw;
            LIST_FOREACH(dsw, &wg->writers, listEntry) {
                if(UA_NodeId_equal(&id, &dsw->head.identifier))
                    return dsw;
            }
        }
    }
    return NULL;
}

void
UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig) {
    UA_String_clear(&pdsConfig->name);
    UA_String_clear(&pdsConfig->dataSetName);
    UA_KeyValueMap_clear(&pdsConfig->dataSetWriterProperties);
    UA_ExtensionObject_clear(&pdsConfig->messageSettings);
    memset(pdsConfig, 0, sizeof(UA_DataSetWriterConfig));
}

static void
UA_DataSetWriter_freezeConfiguration(UA_DataSetWriter *dsw) {
    if(dsw->configurationFrozen)
        return;
    dsw->configurationFrozen = true;
    UA_PublishedDataSet *pds = dsw->connectedDataSet;
    if(!pds) /* Skip for heartbeat writers */
        return;
    pds->configurationFreezeCounter++;
}

static void
UA_DataSetWriter_unfreezeConfiguration(UA_DataSetWriter *dsw) {
    if(!dsw->configurationFrozen)
        return;
    dsw->configurationFrozen = false;
    UA_PublishedDataSet *pds = dsw->connectedDataSet;
    if(!pds) /* Skip for heartbeat writers */
        return;
    pds->configurationFreezeCounter--;
}

UA_StatusCode
UA_DataSetWriter_setPubSubState(UA_PubSubManager *psm, UA_DataSetWriter *dsw,
                                UA_PubSubState targetState) {
    /* Callback to modify the WriterGroup config and change the targetState
     * before the state machine executes */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.beforeStateChangeCallback) {
        server->config.pubSubConfig.
            beforeStateChangeCallback(server, dsw->head.identifier, &targetState);
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_PubSubState oldState = dsw->head.state;
    UA_WriterGroup *wg = dsw->linkedWriterGroup;
    UA_assert(wg);

    /* Custom state machine */
    if(dsw->config.customStateMachine) {
        res = dsw->config.customStateMachine(server, dsw->head.identifier, dsw->config.context,
                                             &dsw->head.state, targetState);
        if(dsw->head.state == UA_PUBSUBSTATE_DISABLED ||
           dsw->head.state == UA_PUBSUBSTATE_ERROR)
            UA_DataSetWriter_unfreezeConfiguration(dsw);
        else
            UA_DataSetWriter_freezeConfiguration(dsw);
        goto finalize_state_machine;
    }

    /* Internal state machine */
    switch(targetState) {
        /* Disabled */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        dsw->head.state = targetState;
        UA_DataSetWriter_unfreezeConfiguration(dsw);
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        if(wg->head.state == UA_PUBSUBSTATE_DISABLED ||
           wg->head.state == UA_PUBSUBSTATE_ERROR ||
           wg->head.state == UA_PUBSUBSTATE_PAUSED) {
            dsw->head.state = UA_PUBSUBSTATE_PAUSED; /* WG is disabled -> paused */
        } else {
            dsw->head.state = wg->head.state; /* WG is enabled -> same state */
        }
        UA_DataSetWriter_freezeConfiguration(dsw);
        break;

    default:
        dsw->head.state = UA_PUBSUBSTATE_ERROR;
        res = UA_STATUSCODE_BADINTERNALERROR;
        UA_DataSetWriter_unfreezeConfiguration(dsw);
        break;
    }

 finalize_state_machine:

    /* No state change has happened */
    if(dsw->head.state == oldState)
        return res;

    UA_LOG_INFO_PUBSUB(psm->logging, dsw, "%s -> %s",
                       UA_PubSubState_name(oldState),
                       UA_PubSubState_name(dsw->head.state));

    /* Inform application about state change */
    if(server->config.pubSubConfig.stateChangeCallback)
        server->config.pubSubConfig.
            stateChangeCallback(server, dsw->head.identifier, dsw->head.state, res);

    return res;
}

UA_StatusCode
UA_DataSetWriter_create(UA_PubSubManager *psm,
                        const UA_NodeId writerGroup, const UA_NodeId dataSet,
                        const UA_DataSetWriterConfig *dswConfig,
                        UA_NodeId *writerIdentifier) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);
    if(!dswConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroup);
    if(!wg)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Make checks for a heartbeat */
    if(UA_NodeId_isNull(&dataSet) && dswConfig->keyFrameCount != 1) {
        UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                              "Adding DataSetWriter failed: DataSet can be null only for "
                              "a heartbeat in which case KeyFrameCount shall be 1");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    if(UA_PubSubState_isEnabled(wg->head.state)) {
        UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                              "Cannot add a DataSetWriter while the "
                              "WriterGroup is enabled");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    UA_PublishedDataSet *pds = NULL;

    if(!UA_NodeId_isNull(&dataSet)) {
        pds = UA_PublishedDataSet_find(psm, dataSet);
        if(!pds) {
            UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                                  "Cannot add the DataSetWriter: "
                                  "The PublishedDataSet was not found");
            return UA_STATUSCODE_BADNOTFOUND;
        }
    }

    UA_DataSetWriter *dsw = (UA_DataSetWriter *)
        UA_calloc(1, sizeof(UA_DataSetWriter));
    if(!dsw)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    dsw->head.componentType = UA_PUBSUBCOMPONENT_DATASETWRITER;
    dsw->linkedWriterGroup = wg;

    /* Copy the config into the new dataSetWriter */
    UA_StatusCode res = UA_DataSetWriterConfig_copy(dswConfig, &dsw->config);
    UA_CHECK_STATUS(res, UA_free(dsw); return res);

    if(pds) {
        /* Save the current version of the connected PublishedDataSet */
        dsw->connectedDataSetVersion = pds->dataSetMetaData.configurationVersion;

        /* Warn about structures containing strings with RawData encoding.
         * MaxStringLength padding is only applied for top-level
         * String/ByteString fields, not for strings nested inside
         * structures. */
        if(dswConfig->dataSetFieldContentMask &
           (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA) {
            for(size_t i = 0; i < pds->dataSetMetaData.fieldsSize; i++) {
                const UA_FieldMetaData *fmd = &pds->dataSetMetaData.fields[i];
                const UA_DataType *type =
                    UA_findDataTypeWithCustom(&fmd->dataType,
                                              psm->sc.server->config.customDataTypes);
                if(type &&
                   (type->typeKind == UA_DATATYPEKIND_STRUCTURE ||
                    type->typeKind == UA_DATATYPEKIND_UNION ||
                    type->typeKind == UA_DATATYPEKIND_OPTSTRUCT) &&
                   typeContainsString(type, 0)) {
                    UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                                          "DataSetWriter field %.*s uses a structure "
                                          "type that contains String/ByteString members. "
                                          "MaxStringLength padding is not applied for "
                                          "strings inside structures with RawData encoding.",
                                          (int)fmd->name.length, fmd->name.data);
                }
            }
        }

        if(psm->sc.server->config.pubSubConfig.enableDeltaFrames) {
            /* Initialize the queue for the last values */
            if(pds->fieldSize > 0) {
                dsw->lastSamples = (UA_DataSetWriterSample*)
                    UA_calloc(pds->fieldSize, sizeof(UA_DataSetWriterSample));
                if(!dsw->lastSamples) {
                    UA_DataSetWriterConfig_clear(&dsw->config);
                    UA_free(dsw);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                dsw->lastSamplesCount = pds->fieldSize;
                for(size_t i = 0; i < dsw->lastSamplesCount; i++) {
                    UA_DataValue_init(&dsw->lastSamples[i].value);
                    dsw->lastSamples[i].valueChanged = false;
                }
            }
        }
        /* Connect PublishedDataSet with DataSetWriter */
        dsw->connectedDataSet = pds;
    } else {
        /* If the dataSet is NULL, we are adding a heartbeat writer */
        dsw->connectedDataSetVersion.majorVersion = 0;
        dsw->connectedDataSetVersion.minorVersion = 0;
        dsw->connectedDataSet = NULL;
    }

    /* Add the new writer to the group in order of the DataSetWriterId. */
    UA_DataSetWriter *elm, *prev = NULL;
    LIST_FOREACH(elm, &wg->writers, listEntry) {
        /* TODO: Issue an error if the DataSetWriterId is not unique */
        if(dsw->config.dataSetWriterId < elm->config.dataSetWriterId)
            break;
        prev = elm;
    }
    if(prev)
        LIST_INSERT_AFTER(prev, dsw, listEntry);
    else
        LIST_INSERT_HEAD(&wg->writers, dsw, listEntry);
    wg->writersCount++;

    /* Add to the information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    res |= addDataSetWriterRepresentation(psm->sc.server, dsw);
#else
    UA_PubSubManager_generateUniqueNodeId(psm, &dsw->head.identifier);
#endif

    /* Cache the log string */
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%SDataSetWriter %N\t| ",
                dsw->linkedWriterGroup->head.logIdString,
                dsw->head.identifier);
    dsw->head.logIdString = UA_STRING_ALLOC(tmpLogIdStr);

    /* Notify the application that a new Writer was created.
     * This may internally adjust the config */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        res = server->config.pubSubConfig.
            componentLifecycleCallback(server, dsw->head.identifier,
                                       UA_PUBSUBCOMPONENT_DATASETWRITER, false);
        if(res != UA_STATUSCODE_GOOD) {
            UA_DataSetWriter_remove(psm, dsw);
            return res;
        }
    }

    UA_LOG_INFO_PUBSUB(psm->logging, dsw,
                       "DataSetWriter created (State: %s)",
                       UA_PubSubState_name(dsw->head.state));

    if(writerIdentifier)
        UA_NodeId_copy(&dsw->head.identifier, writerIdentifier);

    /* Enable the DataSetReader immediately if the enabled flag is set */
    if(dswConfig->enabled)
        UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_OPERATIONAL);

    return res;
}

UA_StatusCode
UA_DataSetWriter_remove(UA_PubSubManager *psm, UA_DataSetWriter *dsw) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_WriterGroup *wg = dsw->linkedWriterGroup;
    UA_assert(wg);

    /* Check if the WriterGroup is enabled. Disallow removal in that case. */
    if(UA_PubSubState_isEnabled(wg->head.state)) {
        UA_LOG_WARNING_PUBSUB(psm->logging, dsw,
                              "Removal of the DataSetWriter not possible while "
                              "the WriterGroup is enabled");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check with the application if we can remove */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        UA_StatusCode res = server->config.pubSubConfig.
            componentLifecycleCallback(server, dsw->head.identifier,
                                       UA_PUBSUBCOMPONENT_DATASETWRITER, true);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Disable and signal to the application */
    UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_DISABLED);

    /* Remove from information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(psm->sc.server, dsw->head.identifier, true);
#endif

    /* Remove DataSetWriter from group */
    LIST_REMOVE(dsw, listEntry);
    wg->writersCount--;

    UA_LOG_INFO_PUBSUB(psm->logging, dsw, "Writer deleted");

    if(psm->sc.server->config.pubSubConfig.enableDeltaFrames) {
        /* Delete lastSamples store */
        for(size_t i = 0; i < dsw->lastSamplesCount; i++) {
            UA_DataValue_clear(&dsw->lastSamples[i].value);
        }
        UA_free(dsw->lastSamples);
        dsw->lastSamples = NULL;
        dsw->lastSamplesCount = 0;
    }

    UA_DataSetWriterConfig_clear(&dsw->config);
    UA_PubSubComponentHead_clear(&dsw->head);
    UA_free(dsw);

    return UA_STATUSCODE_GOOD;
}

/*********************************************************/
/*               PublishValues handling                  */
/*********************************************************/

static UA_StatusCode
UA_PubSubDataSetWriter_generateKeyFrameMessage(UA_PubSubManager *psm,
                                               UA_DataSetMessage *dataSetMessage,
                                               UA_DataSetWriter *dsw) {
    UA_PublishedDataSet *pds = dsw->connectedDataSet;
    if(!pds)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Prepare DataSetMessageContent */
    dataSetMessage->header.dataSetMessageValid = true;
    dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
    dataSetMessage->fieldCount = pds->fieldSize;
    dataSetMessage->data.keyFrameFields = (UA_DataValue *)
            UA_Array_new(pds->fieldSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
    if(!dataSetMessage->data.keyFrameFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Loop over the fields */
    size_t counter = 0;
    UA_DataSetField *dsf;
    TAILQ_FOREACH(dsf, &pds->fields, listEntry) {
        /* Sample the value */
        UA_DataValue *dfv = &dataSetMessage->data.keyFrameFields[counter];
        UA_PubSubDataSetField_sampleValue(psm, dsf, dfv);

        /* Deactivate statuscode? */
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
            dfv->hasStatus = false;

        /* Deactivate timestamps */
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
            dfv->hasSourceTimestamp = false;
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
            dfv->hasSourcePicoseconds = false;
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
            dfv->hasServerTimestamp = false;
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
            dfv->hasServerPicoseconds = false;

        if(psm->sc.server->config.pubSubConfig.enableDeltaFrames) {
            /* Update lastValue store */
            UA_DataValue_clear(&dsw->lastSamples[counter].value);
            UA_DataValue_copy(dfv, &dsw->lastSamples[counter].value);
        }
        counter++;
    }
    return UA_STATUSCODE_GOOD;
}

/* the input message is already initialized and that the method 
 * must not be called twice for the same message */
static UA_StatusCode
UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_PubSubManager *psm,
                                                 UA_DataSetMessage *dsm,
                                                 UA_DataSetWriter *dsw) {
    UA_PublishedDataSet *pds = dsw->connectedDataSet;
    if(!pds)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Prepare DataSetMessageContent */
    dsm->header.dataSetMessageValid = true;
    dsm->header.dataSetMessageType = UA_DATASETMESSAGE_DATADELTAFRAME;
    if(pds->fieldSize == 0)
        return UA_STATUSCODE_GOOD;

    UA_DataSetField *dsf;
    UA_UInt16 counter = 0;
    TAILQ_FOREACH(dsf, &pds->fields, listEntry) {
        /* Sample the value */
        UA_DataValue value;
        UA_DataValue_init(&value);
        UA_PubSubDataSetField_sampleValue(psm, dsf, &value);

        /* Check if the value has changed */
        UA_DataSetWriterSample *ls = &dsw->lastSamples[counter];
        if(!UA_Variant_equal(&ls->value.value, &value.value)) {
            /* increase fieldCount for current delta message */
            dsm->fieldCount++;
            ls->valueChanged = true;

            /* Update last stored sample */
            UA_DataValue_clear(&ls->value);
            ls->value = value;
        } else {
            UA_DataValue_clear(&value);
            ls->valueChanged = false;
        }

        counter++;
    }

    /* Allocate DeltaFrameFields */
    UA_DataSetMessage_DeltaFrameField *deltaFields = (UA_DataSetMessage_DeltaFrameField *)
        UA_calloc(counter, sizeof(UA_DataSetMessage_DeltaFrameField));
    if(!deltaFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    dsm->fieldCount = counter;
    dsm->data.deltaFrameFields = deltaFields;

    size_t currentDeltaField = 0;
    for(size_t i = 0; i < pds->fieldSize; i++) {
        if(!dsw->lastSamples[i].valueChanged)
            continue;

        UA_DataSetMessage_DeltaFrameField *dff = &deltaFields[currentDeltaField];

        dff->index = (UA_UInt16)i;
        UA_DataValue_copy(&dsw->lastSamples[i].value, &dff->value);

        /* Reset the changed flag */
        dsw->lastSamples[i].valueChanged = false;

        /* Deactivate statuscode? */
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
            dff->value.hasStatus = false;

        /* Deactivate timestamps? */
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
            dff->value.hasSourceTimestamp = false;
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
            dff->value.hasServerPicoseconds = false;
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
            dff->value.hasServerTimestamp = false;
        if(((u64)dsw->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
            dff->value.hasServerPicoseconds = false;

        currentDeltaField++;
    }
    return UA_STATUSCODE_GOOD;
}

/* Generate a DataSetMessage for the given writer. */
UA_StatusCode
UA_DataSetWriter_generateDataSetMessage(UA_PubSubManager *psm,
                                        UA_DataSetWriter *dsw,
                                        UA_DataSetMessage *dataSetMessage) {
    UA_EventLoop *el = psm->sc.server->config.eventLoop;

    /* Heartbeat message if no pds is connected */
    UA_PublishedDataSet *pds = dsw->connectedDataSet;

    /* Reset the message */
    memset(dataSetMessage, 0, sizeof(UA_DataSetMessage));

    /* The configuration Flags are included
     * inside the std. defined UA_UadpDataSetWriterMessageDataType */
    UA_UadpDataSetWriterMessageDataType defaultUadpConfiguration;
    UA_UadpDataSetWriterMessageDataType *dsm = NULL;
    UA_JsonDataSetWriterMessageDataType *jsonDsm = NULL;
    const UA_ExtensionObject *ms = &dsw->config.messageSettings;
    if(ms->content.decoded.type == &UA_TYPES[UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE]) {
        dsm = (UA_UadpDataSetWriterMessageDataType*)ms->content.decoded.data; /* type is UADP */
    } else if(ms->content.decoded.type == &UA_TYPES[UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE]) {
        jsonDsm = (UA_JsonDataSetWriterMessageDataType*)ms->content.decoded.data; /* type is JSON */
    } else {
        /* Create default flag configuration if no
         * UadpDataSetWriterMessageDataType was passed in */
        memset(&defaultUadpConfiguration, 0, sizeof(UA_UadpDataSetWriterMessageDataType));
        defaultUadpConfiguration.dataSetMessageContentMask = (UA_UadpDataSetMessageContentMask)
            ((u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP |
             (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION |
             (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION);
        dsm = &defaultUadpConfiguration; /* type is UADP */
    }

    /* The field encoding depends on the flags inside the writer config. */
    if(dsw->config.dataSetFieldContentMask &
       (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA) {
        dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_RAWDATA;
    } else if((u64)dsw->config.dataSetFieldContentMask &
              ((u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP |
               (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS |
               (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS |
               (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE)) {
        dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
    } else {
        dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
    }

    if(dsm) {
        /* Sanity-test the configuration */
        if(dsm->networkMessageNumber != 0 || dsm->dataSetOffset != 0 ||
           dsm->configuredSize != 0) {
            UA_LOG_WARNING_PUBSUB(psm->logging, dsw,
                                  "Static DSM configuration not supported, using defaults");
            dsm->networkMessageNumber = 0;
            dsm->dataSetOffset = 0;
            // dsm->configuredSize = 0;
        }

        /* Std: 'The DataSetMessageContentMask defines the flags for the content
         * of the DataSetMessage header.' */
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION) {
            dataSetMessage->header.configVersionMajorVersionEnabled = true;
            if(!pds) {
                /* Heartbeat */
                dataSetMessage->header.configVersionMajorVersion = 0;
            } else {
                dataSetMessage->header.configVersionMajorVersion =
                    pds->dataSetMetaData.configurationVersion.majorVersion;
            }
        }
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION) {
            dataSetMessage->header.configVersionMinorVersionEnabled = true;
            if(!pds) {
                /* Heartbeat */
                dataSetMessage->header.configVersionMinorVersion = 0;
            } else {
                dataSetMessage->header.configVersionMinorVersion =
                    pds->dataSetMetaData.configurationVersion.minorVersion;
            }
        }

        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
            dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
            dataSetMessage->header.dataSetMessageSequenceNr =
                dsw->actualDataSetMessageSequenceCount;
        }

        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) {
            dataSetMessage->header.timestampEnabled = true;
            dataSetMessage->header.timestamp = el->dateTime_now(el);
        }

        /* TODO: Picoseconds resolution not supported atm */
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) {
            dataSetMessage->header.picoSecondsIncluded = false;
        }

        /* TODO: Statuscode not supported yet */
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_STATUS) {
            dataSetMessage->header.statusEnabled = true;
        }
    } else if(jsonDsm) {
        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) {
            dataSetMessage->header.configVersionMajorVersionEnabled = true;
            dataSetMessage->header.configVersionMinorVersionEnabled = true;
            if(!pds) {
                /* Heartbeat */
                dataSetMessage->header.configVersionMajorVersion = 0;
                dataSetMessage->header.configVersionMinorVersion = 0;
            } else {
                dataSetMessage->header.configVersionMajorVersion =
                    pds->dataSetMetaData.configurationVersion.majorVersion;
                dataSetMessage->header.configVersionMinorVersion =
                    pds->dataSetMetaData.configurationVersion.minorVersion;
            }
       }

        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
            dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
            dataSetMessage->header.dataSetMessageSequenceNr =
                dsw->actualDataSetMessageSequenceCount;
        }

        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_TIMESTAMP) {
            dataSetMessage->header.timestampEnabled = true;
            dataSetMessage->header.timestamp = el->dateTime_now(el);
        }

        /* TODO: Statuscode not supported yet */
        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_STATUS) {
            dataSetMessage->header.statusEnabled = true;
        }
    }

    /* Set the sequence count. Automatically rolls over to zero */
    dsw->actualDataSetMessageSequenceCount++;

    if(!pds) {
        /* Prepare DataSetMessageContent for the heartbeat message */
        dataSetMessage->header.dataSetMessageValid = true;
        dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
        dataSetMessage->fieldCount = 0;
        return UA_STATUSCODE_GOOD;
    }

    /* JSON does not differ between deltaframes and keyframes, only keyframes
     * are currently used. */
    if(dsm && psm->sc.server->config.pubSubConfig.enableDeltaFrames) {
        /* Check if the PublishedDataSet version has changed -> if yes flush the
         * lastValue store and send a KeyFrame */
        if(dsw->connectedDataSetVersion.majorVersion !=
           pds->dataSetMetaData.configurationVersion.majorVersion ||
           dsw->connectedDataSetVersion.minorVersion !=
           pds->dataSetMetaData.configurationVersion.minorVersion) {
            /* Remove old samples */
            for(size_t i = 0; i < dsw->lastSamplesCount; i++)
                UA_DataValue_clear(&dsw->lastSamples[i].value);

            /* Realloc PDS dependent memory */
            dsw->lastSamplesCount = pds->fieldSize;
            UA_DataSetWriterSample *newSamplesArray = (UA_DataSetWriterSample * )
                UA_realloc(dsw->lastSamples,
                           sizeof(UA_DataSetWriterSample) * dsw->lastSamplesCount);
            if(!newSamplesArray)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            dsw->lastSamples = newSamplesArray;
            memset(dsw->lastSamples, 0,
                   sizeof(UA_DataSetWriterSample) * dsw->lastSamplesCount);

            dsw->connectedDataSetVersion =
                pds->dataSetMetaData.configurationVersion;
            UA_PubSubDataSetWriter_generateKeyFrameMessage(psm, dataSetMessage, dsw);
            dsw->deltaFrameCounter = 0;
            return UA_STATUSCODE_GOOD;
        }

        /* The standard defines: if a PDS contains only one fields no delta messages
         * should be generated because they need more memory than a keyframe with 1
         * field. */
        if(pds->fieldSize > 1 && dsw->deltaFrameCounter > 0 &&
           dsw->deltaFrameCounter <= dsw->config.keyFrameCount) {
            UA_PubSubDataSetWriter_generateDeltaFrameMessage(psm, dataSetMessage, dsw);
            dsw->deltaFrameCounter++;
            return UA_STATUSCODE_GOOD;
        }

        dsw->deltaFrameCounter = 1;
    }

    return UA_PubSubDataSetWriter_generateKeyFrameMessage(psm, dataSetMessage, dsw);
}

/**************/
/* Server API */
/**************/

UA_StatusCode
UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dswId,
                                 UA_DataSetWriterConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_DataSetWriter *dsw = UA_DataSetWriter_find(getPSM(server), dswId);
    UA_StatusCode res = (dsw) ?
        UA_DataSetWriterConfig_copy(&dsw->config, config) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getDataSetWriterState(UA_Server *server, const UA_NodeId dswId,
                               UA_PubSubState *state) {
    if(!server || !state)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_DataSetWriter *dsw = UA_DataSetWriter_find(getPSM(server), dswId);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(dsw) {
        *state = dsw->head.state;
        res = UA_STATUSCODE_GOOD;
    }
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_enableDataSetWriter(UA_Server *server, const UA_NodeId dswId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetWriter *dsw = UA_DataSetWriter_find(psm, dswId);
    UA_StatusCode ret = (dsw) ?
        UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_OPERATIONAL) :
        UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return ret;
}

UA_StatusCode
UA_Server_disableDataSetWriter(UA_Server *server, const UA_NodeId dswId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetWriter *dsw = UA_DataSetWriter_find(psm, dswId);
    UA_StatusCode ret = (dsw) ?
        UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_DISABLED) :
        UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return ret;
}

UA_StatusCode
UA_Server_addDataSetWriter(UA_Server *server,
                           const UA_NodeId writerGroup, const UA_NodeId dataSet,
                           const UA_DataSetWriterConfig *dataSetWriterConfig,
                           UA_NodeId *writerIdentifier) {
    if(!server || !dataSetWriterConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    if(!psm) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    /* Delete the reserved IDs if the related session no longer exists. */
    UA_PubSubManager_freeIds(psm);
    UA_StatusCode res = UA_DataSetWriter_create(psm, writerGroup, dataSet,
                                                dataSetWriterConfig, writerIdentifier);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dswId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetWriter *dsw = UA_DataSetWriter_find(psm, dswId);
    UA_StatusCode res = (dsw) ?
        UA_DataSetWriter_remove(psm, dsw) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_updateDataSetWriterConfig(UA_Server *server, const UA_NodeId dswId,
                                    const UA_DataSetWriterConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);

    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetWriter *dsw = UA_DataSetWriter_find(psm, dswId);
    if(!dsw) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    if(UA_PubSubState_isEnabled(dsw->head.state)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, dsw,
                            "The DataSetWriter must be disabled to update the config");
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Make checks for a heartbeat */
    if(!dsw->connectedDataSet && config->keyFrameCount != 1) {
        UA_LOG_ERROR_PUBSUB(psm->logging, dsw,
                            "Adding DataSetWriter failed: DataSet can be null only for "
                            "a heartbeat in which case KeyFrameCount shall be 1");
        unlockServer(server);
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* Copy the config into the dsw */
    UA_DataSetWriterConfig newConfig;
    UA_StatusCode res = UA_DataSetWriterConfig_copy(config, &newConfig);
    if(res == UA_STATUSCODE_GOOD) {
        UA_DataSetWriterConfig_clear(&dsw->config);
        dsw->config = newConfig;
    }

    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_writergroup.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2025 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */


#ifdef UA_ENABLE_PUBSUB_SKS
#endif

static UA_StatusCode
encryptAndSign(UA_WriterGroup *wg, const UA_NetworkMessage *nm,
               UA_Byte *signStart, UA_Byte *encryptStart,
               UA_Byte *msgEnd);

static UA_StatusCode
generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
                       UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
                       UA_ExtensionObject *messageSettings,
                       UA_ExtensionObject *transportSettings,
                       UA_NetworkMessage *networkMessage);

static void
UA_WriterGroup_disconnect(UA_WriterGroup *wg);

static UA_StatusCode
UA_WriterGroup_connect(UA_PubSubManager *psm, UA_WriterGroup *wg,
                       UA_Boolean validate);

static UA_Boolean
UA_WriterGroup_canConnect(UA_WriterGroup *wg) {
    /* Already connected */
    if(wg->sendChannel != 0)
        return false;

    /* Is this a WriterGroup with custom TransportSettings beyond the
     * PubSubConnection? */
    if(wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return false;

    return true;
}

UA_StatusCode
UA_WriterGroup_addPublishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Already registered */
    if(wg->publishCallbackId != 0)
        return UA_STATUSCODE_GOOD;

    /* Use EventLoop for cyclic callbacks */
    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    return el->addTimer(el, (UA_Callback)UA_WriterGroup_publishCallback,
                        psm, wg, wg->config.publishingInterval,
                        NULL /* TODO: use basetime */,
                        UA_TIMERPOLICY_CURRENTTIME,
                        &wg->publishCallbackId);
}

void
UA_WriterGroup_removePublishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg) {
    if(wg->publishCallbackId == 0)
        return;
    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    if(UA_LIKELY(el != NULL))
        el->removeTimer(el, wg->publishCallbackId);
    wg->publishCallbackId = 0;
}

#ifdef UA_ENABLE_PUBSUB_SKS
static UA_StatusCode
writerGroupAttachSKSKeystorage(UA_PubSubManager *psm, UA_WriterGroup *wg) {
    /* No SecurityGroup defined */
    if(UA_String_isEmpty(&wg->config.securityGroupId) || !wg->config.securityPolicy)
        return UA_STATUSCODE_GOOD;

    /* KeyStorage already connected */
    if(wg->keyStorage)
        return UA_STATUSCODE_GOOD;

    /* Does the key storage already exist? */
    wg->keyStorage = UA_PubSubKeyStorage_find(psm, wg->config.securityGroupId);
    if(wg->keyStorage) {
        wg->keyStorage->referenceCount++; /* Increase the ref count */
        return UA_STATUSCODE_GOOD;
    }

    /* Create a new key storage */
    wg->keyStorage = (UA_PubSubKeyStorage *)UA_calloc(1, sizeof(UA_PubSubKeyStorage));
    if(!wg->keyStorage)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Initialize the KeyStorage */
    UA_StatusCode res =
        UA_PubSubKeyStorage_init(psm, wg->keyStorage, &wg->config.securityGroupId,
                                 wg->config.securityPolicy, 0, 0);
    if(res != UA_STATUSCODE_GOOD) {
        UA_PubSubKeyStorage_delete(psm, wg->keyStorage);
        wg->keyStorage = NULL;
        return res;
    }

    wg->keyStorage->referenceCount++; /* Increase the ref count */
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
validateWriterGroupConfig(UA_PubSubManager *psm, UA_PubSubComponentHead *logHead,
                          const UA_WriterGroupConfig *config) {
    const UA_ExtensionObject *ms = &config->messageSettings;
    if(ms->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return UA_STATUSCODE_GOOD;

    if(config->encodingMimeType == UA_PUBSUB_ENCODING_JSON) {
        if(!UA_ExtensionObject_hasDecodedType(ms,
                &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE])) {
            UA_LOG_WARNING_PUBSUB(psm->logging, (UA_PubSubConnection*)logHead,
                                  "WriTerGroupConfig MessageSettings need to be "
                                  "of type JSONWriterGroupMessageDataType");
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }
    } else if(config->encodingMimeType == UA_PUBSUB_ENCODING_UADP) {
        if(!UA_ExtensionObject_hasDecodedType(ms,
                &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])) {
            UA_LOG_WARNING_PUBSUB(psm->logging, (UA_PubSubConnection*)logHead,
                                  "WriTerGroupConfig MessageSettings need to be "
                                  "of type UADPWriterGroupMessageDataType");
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }
    } else {
        UA_LOG_WARNING_PUBSUB(psm->logging, (UA_PubSubConnection*)logHead,
                              "Wrong encoding MIME-type");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_WriterGroup_create(UA_PubSubManager *psm, const UA_NodeId connection,
                      const UA_WriterGroupConfig *config,
                      UA_NodeId *writerGroupIdentifier) {
    /* Delete the reserved IDs if the related session no longer exists. */
    UA_PubSubManager_freeIds(psm);
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Search the connection by the given connectionIdentifier */
    UA_PubSubConnection *c = UA_PubSubConnection_find(psm, connection);
    if(!c)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Validate messageSettings type */
    UA_StatusCode res = validateWriterGroupConfig(psm, &c->head, config);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Allocate new WriterGroup */
    UA_WriterGroup *wg = (UA_WriterGroup*)UA_calloc(1, sizeof(UA_WriterGroup));
    if(!wg)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    wg->head.componentType = UA_PUBSUBCOMPONENT_WRITERGROUP;
    wg->linkedConnection = c;

    /* Deep copy of the config */
    res = UA_WriterGroupConfig_copy(config, &wg->config);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(wg);
        return res;
    }

    /* Attach to the connection */
    LIST_INSERT_HEAD(&c->writerGroups, wg, listEntry);
    c->writerGroupsSize++;

    /* Add representation / create unique identifier */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    res = addWriterGroupRepresentation(psm->sc.server, wg);
    if(res != UA_STATUSCODE_GOOD) {
        UA_WriterGroup_remove(psm, wg);
        return res;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(psm, &wg->head.identifier);
#endif

    /* Cache the log string */
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%SWriterGroup %N\t| ",
                c->head.logIdString, wg->head.identifier);
    wg->head.logIdString = UA_STRING_ALLOC(tmpLogIdStr);

    /* Validate the connection settings */
    res = UA_WriterGroup_connect(psm, wg, true);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "Could not validate the connection parameters");
        UA_WriterGroup_remove(psm, wg);
        return res;
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    if(config->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       config->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        res = writerGroupAttachSKSKeystorage(psm, wg);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_PUBSUB(psm->logging, wg, "Attaching the SKS KeyStorage failed");
            UA_WriterGroup_remove(psm, wg);
            return res;
        }
    }
#endif

    /* Notify the application that a new WriterGroup was created.
     * This may internally adjust the config */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        res = server->config.pubSubConfig.
            componentLifecycleCallback(server, wg->head.identifier,
                                       UA_PUBSUBCOMPONENT_WRITERGROUP, false);
        if(res != UA_STATUSCODE_GOOD) {
            UA_WriterGroup_remove(psm, wg);
            return res;
        }
    }

    UA_LOG_INFO_PUBSUB(psm->logging, wg, "WriterGroup created (State: %s)",
                       UA_PubSubState_name(wg->head.state));

    /* Trigger the connection state machine. It might open a socket only when
     * the first WriterGroup is attached. */
    if(config->enabled)
        UA_PubSubConnection_setPubSubState(psm, c, c->head.state);

    /* Copying a numeric NodeId always succeeds */
    if(writerGroupIdentifier)
        UA_NodeId_copy(&wg->head.identifier, writerGroupIdentifier);

    /* Enable the WriterGroup immediately if the enabled flag is set */
    if(config->enabled)
        UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_OPERATIONAL);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_WriterGroup_remove(UA_PubSubManager *psm, UA_WriterGroup *wg) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Check with the application if we can remove */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        UA_StatusCode res = server->config.pubSubConfig.
            componentLifecycleCallback(server, wg->head.identifier,
                                       UA_PUBSUBCOMPONENT_WRITERGROUP, true);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    UA_PubSubConnection *connection = wg->linkedConnection;
    UA_assert(connection);

    /* Disable (and disconnect) and set the deleteFlag. This prevents a
     * reconnect and triggers the deletion when the last open socket is
     * closed. */
    wg->deleteFlag = true;
    UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_DISABLED);

    UA_DataSetWriter *dsw, *dsw_tmp;
    LIST_FOREACH_SAFE(dsw, &wg->writers, listEntry, dsw_tmp) {
        UA_DataSetWriter_remove(psm, dsw);
    }

    if(wg->config.securityPolicy && wg->securityPolicyContext) {
        UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;
        sp->deleteGroupContext(sp, wg->securityPolicyContext);
        wg->securityPolicyContext = NULL;
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    if(wg->keyStorage) {
        UA_PubSubKeyStorage_detachKeyStorage(psm, wg->keyStorage);
        wg->keyStorage = NULL;
    }
#endif

    if(wg->sendChannel == 0) {
        /* Unlink from the connection */
        LIST_REMOVE(wg, listEntry);
        connection->writerGroupsSize--;
        wg->linkedConnection = NULL;

        /* Actually remove the WriterGroup */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
        deleteNode(psm->sc.server, wg->head.identifier, true);
#endif

        UA_LOG_INFO_PUBSUB(psm->logging, wg, "WriterGroup deleted");

        UA_WriterGroupConfig_clear(&wg->config);
        UA_PubSubComponentHead_clear(&wg->head);
        UA_free(wg);
    }

    /* Update the connection state */
    UA_PubSubConnection_setPubSubState(psm, connection, connection->head.state);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src,
                          UA_WriterGroupConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_WriterGroupConfig));
    res |= UA_String_copy(&src->name, &dst->name);
    res |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
    res |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
    res |= UA_KeyValueMap_copy(&src->groupProperties, &dst->groupProperties);
    res |= UA_String_copy(&src->securityGroupId, &dst->securityGroupId);
    if(res != UA_STATUSCODE_GOOD)
        UA_WriterGroupConfig_clear(dst);
    return res;
}

UA_WriterGroup *
UA_WriterGroup_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            if(UA_NodeId_equal(&id, &wg->head.identifier))
                return wg;
        }
    }
    return NULL;
}

UA_StatusCode
UA_WriterGroup_setEncryptionKeys(UA_PubSubManager *psm, UA_WriterGroup *wg,
                                 UA_UInt32 securityTokenId,
                                 const UA_ByteString signingKey,
                                 const UA_ByteString encryptingKey,
                                 const UA_ByteString keyNonce) {
    if(wg->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) {
        UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                              "JSON encoding is enabled. The message security "
                              "iis only defined for the UADP message mapping.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(!wg->config.securityPolicy) {
        UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                              "No SecurityPolicy configured for the WriterGroup");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(securityTokenId != wg->securityTokenId) {
        wg->securityTokenId = securityTokenId;
        wg->nonceSequenceNumber = 1;
    }

    UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;
    UA_StatusCode res = UA_STATUSCODE_BAD;
    if(!wg->securityPolicyContext) {
        /* Create a new context */
        res = sp->newGroupContext(sp, &signingKey, &encryptingKey, &keyNonce,
                                  &wg->securityPolicyContext);
    } else {
        /* Update the context */
        res = sp->setSecurityKeys(sp, wg->securityPolicyContext, &signingKey,
                                  &encryptingKey, &keyNonce);
    }

    return (res == UA_STATUSCODE_GOOD) ?
        UA_WriterGroup_setPubSubState(psm, wg, wg->head.state) : res;
}

void
UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig) {
    UA_String_clear(&writerGroupConfig->name);
    UA_ExtensionObject_clear(&writerGroupConfig->transportSettings);
    UA_ExtensionObject_clear(&writerGroupConfig->messageSettings);
    UA_KeyValueMap_clear(&writerGroupConfig->groupProperties);
    UA_String_clear(&writerGroupConfig->securityGroupId);
    memset(writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
}

UA_StatusCode
UA_WriterGroup_setPubSubState(UA_PubSubManager *psm, UA_WriterGroup *wg,
                              UA_PubSubState targetState) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    if(wg->deleteFlag && targetState != UA_PUBSUBSTATE_DISABLED) {
        UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                              "The WriterGroup is being deleted. Can only be disabled.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Callback to modify the WriterGroup config and change the targetState
     * before the state machine executes */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.beforeStateChangeCallback) {
        server->config.pubSubConfig.
            beforeStateChangeCallback(server, wg->head.identifier, &targetState);
    }

    /* Are we doing a top-level state update or recursively? */
    UA_Boolean isTransient = wg->head.transientState;
    wg->head.transientState = true;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubState oldState = wg->head.state;
    UA_PubSubConnection *connection = wg->linkedConnection;

    /* Custom state machine */
    if(wg->config.customStateMachine) {
        ret = wg->config.customStateMachine(server, wg->head.identifier, wg->config.context,
                                            &wg->head.state, targetState);
        goto finalize_state_machine;
    }

    /* Internal state machine */
    switch(targetState) {
        /* Disabled or Error */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        wg->head.state = targetState;
        UA_WriterGroup_disconnect(wg);
        UA_WriterGroup_removePublishCallback(psm, wg);
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        /* PAUSED has no open connections and periodic callbacks */
        if(psm->sc.state != UA_LIFECYCLESTATE_STARTED) {
            /* Avoid repeat warnings */
            if(oldState != UA_PUBSUBSTATE_PAUSED) {
                UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                                      "Cannot enable the WriterGroup while the "
                                      "server is not running -> Paused State");
            }
            wg->head.state = UA_PUBSUBSTATE_PAUSED;
            UA_WriterGroup_disconnect(wg);
            UA_WriterGroup_removePublishCallback(psm, wg);
            break;
        }

        if(connection->head.state != UA_PUBSUBSTATE_OPERATIONAL) {
            wg->head.state = UA_PUBSUBSTATE_PAUSED;
            UA_WriterGroup_disconnect(wg);
            UA_WriterGroup_removePublishCallback(psm, wg);
            break;
        }

        wg->head.state = UA_PUBSUBSTATE_OPERATIONAL;

        /* Not fully connected -> connect */
        if(UA_WriterGroup_canConnect(wg)) {
            ret = UA_WriterGroup_connect(psm, wg, false);
            if(ret != UA_STATUSCODE_GOOD)
                break;
        }

        /* Security Mode not set-> PreOperational */
        if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE &&
           wg->securityTokenId == 0)
            wg->head.state = UA_PUBSUBSTATE_PREOPERATIONAL;

        /* Enable publish callback if operational */
        if(wg->head.state == UA_PUBSUBSTATE_OPERATIONAL)
            ret = UA_WriterGroup_addPublishCallback(psm, wg);
        break;

        /* Unknown case */
    default:
        ret = UA_STATUSCODE_BADINTERNALERROR;
        break;
    }

    /* Failure */
    if(ret != UA_STATUSCODE_GOOD) {
        wg->head.state = UA_PUBSUBSTATE_ERROR;
        UA_WriterGroup_disconnect(wg);
        UA_WriterGroup_removePublishCallback(psm, wg);
    }

 finalize_state_machine:

    /* Only the top-level state update (if recursive calls are happening)
     * notifies the application and updates Reader and WriterGroups */
    wg->head.transientState = isTransient;
    if(wg->head.transientState)
        return ret;

    /* No state change has happened */
    if(wg->head.state == oldState)
        return ret;

    UA_LOG_INFO_PUBSUB(psm->logging, wg, "%s -> %s",
                       UA_PubSubState_name(oldState),
                       UA_PubSubState_name(wg->head.state));

    /* Inform the application about state change */
    if(server->config.pubSubConfig.stateChangeCallback)
        server->config.pubSubConfig.
            stateChangeCallback(server, wg->head.identifier, wg->head.state, ret);

    /* Children evaluate their state machine after the state change of the parent.
     * Keep the current child state as the target state for the child. */
    UA_DataSetWriter *writer;
    LIST_FOREACH(writer, &wg->writers, listEntry) {
        if(psm->pubSubInitialSetupMode && writer->config.enabled) {
            UA_DataSetWriter_setPubSubState(psm, writer, UA_PUBSUBSTATE_OPERATIONAL);
        } else {
            UA_DataSetWriter_setPubSubState(psm, writer, writer->head.state);
        }
    }

    /* Update the PubSubManager state. It will go from STOPPING to STOPPED when
     * the last socket has closed. */
    UA_PubSubManager_setState(psm, psm->sc.state);

    return ret;
}

static UA_StatusCode
encryptAndSign(UA_WriterGroup *wg, const UA_NetworkMessage *nm,
               UA_Byte *signStart, UA_Byte *encryptStart,
               UA_Byte *msgEnd) {
    UA_StatusCode rv;
    void *channelContext = wg->securityPolicyContext;

    UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;

    if(nm->securityHeader.networkMessageEncrypted) {
        /* Set the temporary MessageNonce in the SecurityPolicy */
        const UA_ByteString nonce = {
            (size_t)nm->securityHeader.messageNonceSize,
            (UA_Byte*)(uintptr_t)nm->securityHeader.messageNonce
        };
        rv = sp->setMessageNonce(sp, channelContext, &nonce);
        UA_CHECK_STATUS(rv, return rv);

        /* The encryption is done in-place, no need to encode again */
        UA_ByteString toBeEncrypted =
            {(uintptr_t)msgEnd - (uintptr_t)encryptStart, encryptStart};
        rv = sp->encrypt(sp, channelContext, &toBeEncrypted);
        UA_CHECK_STATUS(rv, return rv);
    }

    if(nm->securityHeader.networkMessageSigned) {
        UA_ByteString toBeSigned =
            {(uintptr_t)msgEnd - (uintptr_t)signStart, signStart};

        size_t sigSize = sp->getSignatureSize(sp, channelContext);
        UA_ByteString signature = {sigSize, msgEnd};

        rv = sp->sign(sp, channelContext, &toBeSigned, &signature);
        UA_CHECK_STATUS(rv, return rv);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
encodeNetworkMessage(UA_WriterGroup *wg, PubSubEncodeCtx *ctx,
                     UA_NetworkMessage *nm, UA_ByteString *buf) {
    UA_Byte *networkMessageStart = buf->data;
    UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(ctx, nm);
    UA_CHECK_STATUS(rv, return rv);

    UA_Byte *payloadStart = ctx->ctx.pos;
    rv = UA_NetworkMessage_encodePayload(ctx, nm);
    UA_CHECK_STATUS(rv, return rv);

    rv = UA_NetworkMessage_encodeFooters(ctx, nm);
    UA_CHECK_STATUS(rv, return rv);

    /* Encrypt and Sign the message */
    UA_Byte *footerEnd = ctx->ctx.pos;
    return encryptAndSign(wg, nm, networkMessageStart, payloadStart, footerEnd);
}

static void
sendNetworkMessageBuffer(UA_PubSubManager *psm, UA_WriterGroup *wg, 
                         UA_PubSubConnection *connection, uintptr_t connectionId,
                         UA_ByteString *buffer) {
    UA_StatusCode res = connection->cm->
        sendWithConnection(connection->cm, connectionId,
                           &UA_KEYVALUEMAP_NULL, buffer);

    /* Failure, set the WriterGroup into an error mode */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "Sending NetworkMessage failed");
        UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_ERROR);
        UA_PubSubConnection_setPubSubState(psm, connection, UA_PUBSUBSTATE_ERROR);
        return;
    }

    /* Sending successful - increase the sequence number */
    wg->sequenceNumber++;
}

#ifdef UA_ENABLE_JSON_ENCODING
static UA_StatusCode
sendNetworkMessageJson(UA_PubSubManager *psm, UA_PubSubConnection *connection, UA_WriterGroup *wg,
                       UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) {
    /* Prepare the NetworkMessage */
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));
    nm.version = 1;
    nm.networkMessageType = UA_NETWORKMESSAGE_DATASET;
    nm.payloadHeaderEnabled = true;
    nm.payload.dataSetMessages = dsm;
    nm.messageCount = dsmCount;
    nm.publisherIdEnabled = true;
    nm.publisherId = connection->config.publisherId;

    for(size_t i = 0; i < dsmCount; i++)
        nm.dataSetWriterIds[i] = writerIds[i];

    PubSubEncodeJsonCtx ctx;
    memset(&ctx, 0, sizeof(PubSubEncodeJsonCtx));

    /* Prepare the metadata to encode the DataSetMessages */
    size_t i = 0;
    UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, wg->writersCount);
    memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * wg->writersCount);
    ctx.eo.metaData = emd;
    ctx.eo.metaDataSize = wg->writersCount;
    UA_DataSetWriter *dsw;
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        emd[i].dataSetWriterId = dsw->config.dataSetWriterId;
        UA_PublishedDataSet *pds = dsw->connectedDataSet;
        if(pds) {
            emd[i].fields = pds->dataSetMetaData.fields;
            emd[i].fieldsSize = pds->dataSetMetaData.fieldsSize;
        }
        i++;
    }

    /* Compute the message length */
    size_t msgSize = UA_NetworkMessage_calcSizeJson(&nm, &ctx.eo, NULL);

    UA_ConnectionManager *cm = connection->cm;
    if(!cm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Select the wg sendchannel if configured */
    uintptr_t sendChannel = connection->sendChannel;
    if(wg->sendChannel != 0)
        sendChannel = wg->sendChannel;
    if(sendChannel == 0) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg, "Cannot send, no open connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Allocate the buffer */
    UA_ByteString buf;
    UA_StatusCode res = cm->allocNetworkBuffer(cm, sendChannel, &buf, msgSize);
    UA_CHECK_STATUS(res, return res);

    /* Encode the message */
    ctx.ctx.pos = buf.data;
    ctx.ctx.end = &buf.data[msgSize];
    res = UA_NetworkMessage_encodeJsonInternal(&ctx, &nm);
    if(res != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, sendChannel, &buf);
        return res;
    }
    UA_assert(ctx.ctx.pos == ctx.ctx.end);

    /* Send the prepared messages */
    sendNetworkMessageBuffer(psm, wg, connection, sendChannel, &buf);
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
                       UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
                       UA_ExtensionObject *messageSettings,
                       UA_ExtensionObject *transportSettings,
                       UA_NetworkMessage *nm) {
    UA_UadpWriterGroupMessageDataType tmpWgm;
    UA_UadpWriterGroupMessageDataType *wgm;
    if(UA_ExtensionObject_hasDecodedType(messageSettings,
           &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])) {
        wgm = (UA_UadpWriterGroupMessageDataType*)messageSettings->content.decoded.data;
    } else {
        /* Use default settings */
        UA_UadpWriterGroupMessageDataType_init(&tmpWgm);
        wgm = &tmpWgm;
    }

    nm->publisherIdEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID) != 0;
    nm->groupHeaderEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER) != 0;
    nm->groupHeader.writerGroupIdEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID) != 0;
    nm->groupHeader.groupVersionEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPVERSION) != 0;
    nm->groupHeader.networkMessageNumberEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_NETWORKMESSAGENUMBER) != 0;
    nm->groupHeader.sequenceNumberEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_SEQUENCENUMBER) != 0;
    nm->payloadHeaderEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER) != 0;
    nm->timestampEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_TIMESTAMP) != 0;
    nm->picosecondsEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PICOSECONDS) != 0;
    nm->dataSetClassIdEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_DATASETCLASSID) != 0;
    nm->promotedFieldsEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PROMOTEDFIELDS) != 0;

    /* Set the SecurityHeader */
    if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
        nm->securityEnabled = true;
        nm->securityHeader.networkMessageSigned = true;
        if(wg->config.securityMode >= UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
            nm->securityHeader.networkMessageEncrypted = true;
        nm->securityHeader.securityTokenId = wg->securityTokenId;

        /* Generate the MessageNonce. Four random bytes followed by a four-byte
         * sequence number */
        UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;
        UA_ByteString nonce = {4, nm->securityHeader.messageNonce};
        UA_StatusCode rv = sp->generateNonce(sp, wg->securityPolicyContext, &nonce);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
        UA_Byte *pos = &nm->securityHeader.messageNonce[4];
        const UA_Byte *end = &nm->securityHeader.messageNonce[8];
        UA_UInt32_encodeBinary(&wg->nonceSequenceNumber, &pos, end);
        nm->securityHeader.messageNonceSize = 8;
    }

    nm->version = 1;
    nm->networkMessageType = UA_NETWORKMESSAGE_DATASET;
    /* shallow copy of the PublisherId from connection configuration
        -> the configuration needs to be stable during publishing process
        -> it must not be cleaned after network message has been sent */
    nm->publisherId = connection->config.publisherId;

    if(nm->groupHeader.sequenceNumberEnabled)
        nm->groupHeader.sequenceNumber = wg->sequenceNumber;

    if(nm->groupHeader.groupVersionEnabled)
        nm->groupHeader.groupVersion = wgm->groupVersion;

    nm->groupHeader.writerGroupId = wg->config.writerGroupId;
    /* number of the NetworkMessage inside a PublishingInterval */
    nm->groupHeader.networkMessageNumber = 1;
    nm->payload.dataSetMessages = dsm;
    nm->messageCount = dsmCount;

    for(size_t i = 0; i < dsmCount; i++)
        nm->dataSetWriterIds[i] = writerIds[i];

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sendNetworkMessageBinary(UA_PubSubManager *psm, UA_PubSubConnection *connection,
                         UA_WriterGroup *wg, UA_DataSetMessage *dsm, UA_UInt16 *writerIds,
                         UA_Byte dsmCount) {
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));

    /* Fill the message structure */
    UA_StatusCode rv =
        generateNetworkMessage(connection, wg, dsm, writerIds, dsmCount,
                               &wg->config.messageSettings,
                               &wg->config.transportSettings, &nm);
    UA_CHECK_STATUS(rv, return rv);

    PubSubEncodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubEncodeCtx));

    /* Prepare the metadata with information from the readers to decode the
     * DataSetMessages */
    size_t i = 0;
    UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, wg->writersCount);
    memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * wg->writersCount);
    ctx.eo.metaData = emd;
    ctx.eo.metaDataSize = wg->writersCount;
    UA_DataSetWriter *dsw;
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        emd[i].dataSetWriterId = dsw->config.dataSetWriterId;
        UA_PublishedDataSet *pds = dsw->connectedDataSet;
        if(pds) {
            emd[i].fields = pds->dataSetMetaData.fields;
            emd[i].fieldsSize = pds->dataSetMetaData.fieldsSize;
        }
        i++;
    }

    /* Compute the message size. Add the overhead for the security signature.
     * There is no padding and the encryption incurs no size overhead. */
    size_t msgSize = UA_NetworkMessage_calcSizeBinaryInternal(&ctx, &nm);
    if(msgSize == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Add the overhead for the security signature.
     * There is no padding and the encryption incurs no size overhead. */
    if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
        UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;
        msgSize += sp->getSignatureSize(sp, sp->policyContext);
    }

    UA_ConnectionManager *cm = connection->cm;
    if(!cm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Select the wg sendchannel if configured */
    uintptr_t sendChannel = connection->sendChannel;
    if(wg->sendChannel != 0)
        sendChannel = wg->sendChannel;
    if(sendChannel == 0) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg, "Cannot send, no open connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Allocate the buffer. Allocate on the stack if the buffer is small. */
    UA_ByteString buf = UA_BYTESTRING_NULL;
    rv = cm->allocNetworkBuffer(cm, sendChannel, &buf, msgSize);
    UA_CHECK_STATUS(rv, return rv);

    /* Encode and encrypt the message */
    ctx.ctx.pos = buf.data;
    ctx.ctx.end = &buf.data[buf.length];
    rv = encodeNetworkMessage(wg, &ctx, &nm, &buf);
    if(rv != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, sendChannel, &buf);
        return rv;
    }

    /* Send out the message */
    sendNetworkMessageBuffer(psm, wg, connection, sendChannel, &buf);
    return UA_STATUSCODE_GOOD;
}

static void
sendNetworkMessage(UA_PubSubManager *psm, UA_WriterGroup *wg, UA_PubSubConnection *connection,
                   UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) {
    if(dsmCount >= UA_NETWORKMESSAGE_MAXMESSAGECOUNT) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "More DataSetMessages than allowed in "
                            "UA_NETWORKMESSAGE_MAXMESSAGECOUNT");
        UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_ERROR);
        return;
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(wg->config.encodingMimeType) {
    case UA_PUBSUB_ENCODING_UADP:
        res = sendNetworkMessageBinary(psm, connection, wg, dsm, writerIds, dsmCount);
        break;
#ifdef UA_ENABLE_JSON_ENCODING
    case UA_PUBSUB_ENCODING_JSON:
        res = sendNetworkMessageJson(psm, connection, wg, dsm, writerIds, dsmCount);
        break;
#endif
    default:
        res = UA_STATUSCODE_BADNOTSUPPORTED;
        break;
    }

    /* If sending failed, disable all writer of the writergroup */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "PubSub Publish: Could not send a NetworkMessage "
                            "with status code %s", UA_StatusCode_name(res));
        UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_ERROR);
    }
}

/* This callback triggers the collection and publish of NetworkMessages and the
 * contained DataSetMessages. */
void
UA_WriterGroup_publishCallback(UA_PubSubManager *psm, UA_WriterGroup *wg) {
    UA_assert(wg != NULL);
    UA_assert(psm != NULL);

    UA_LOG_DEBUG_PUBSUB(psm->logging, wg, "Publish Callback");

    lockServer(psm->sc.server);

    /* Find the connection associated with the writer */
    UA_PubSubConnection *connection = wg->linkedConnection;
    if(!connection) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "Publish failed. PubSubConnection invalid");
        UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_ERROR);
        unlockServer(psm->sc.server);
        return;
    }

    /* How many DSM can be sent in one NM? */
    UA_Byte maxDSM = (UA_Byte)wg->config.maxEncapsulatedDataSetMessageCount;
    if(wg->config.maxEncapsulatedDataSetMessageCount > UA_BYTE_MAX)
        maxDSM = UA_BYTE_MAX;
    if(maxDSM == 0)
        maxDSM = 1; /* Send at least one dsm */

    /* It is possible to put several DataSetMessages into one NetworkMessage.
     * But only if they do not contain promoted fields. NM with promoted fields
     * are sent out right away. The others are kept in a buffer for
     * "batching". */
    size_t dsmCount = 0;
    UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount);
    UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount);

    size_t enabledWriters = 0;

    UA_DataSetWriter *dsw;
    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        if(dsw->head.state != UA_PUBSUBSTATE_OPERATIONAL)
            continue;

        enabledWriters++;

        /* PDS can be NULL -> Heartbeat */
        UA_PublishedDataSet *pds = dsw->connectedDataSet;

        /* Generate the DSM */
        dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
        UA_StatusCode res =
            UA_DataSetWriter_generateDataSetMessage(psm, dsw, &dsmStore[dsmCount]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_PUBSUB(psm->logging, dsw,
                                "PubSub Publish: DataSetMessage creation failed");
            UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_ERROR);
            continue;
        }

        /* There is no promoted field -> send right away */
        if(pds && pds->promotedFieldsCount > 0) {
            wg->lastPublishTimeStamp = el->dateTime_nowMonotonic(el);
            sendNetworkMessage(psm, wg, connection, &dsmStore[dsmCount],
                               &dsWriterIds[dsmCount], 1);

            UA_DataSetMessage_clear(&dsmStore[dsmCount]);
            continue; /* Don't increase the dsmCount, reuse the slot */
        }

        dsmCount++;
    }

    /* No enabled Writers */
    if(enabledWriters == 0) {
        UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                              "Cannot publish -- No Writers are enabled");
        unlockServer(psm->sc.server);
        return;
    }

    /* Send the NetworkMessages with batched DataSetMessages */
    UA_Byte nmDsmCount = 0;
    for(size_t i = 0; i < dsmCount; i += nmDsmCount) {
        /* How many dsm are batched in this iteration? */
        nmDsmCount = (i + maxDSM > dsmCount) ? (UA_Byte)(dsmCount - i) : maxDSM;
        wg->lastPublishTimeStamp = el->dateTime_nowMonotonic(el);
        /* Send the batched messages */
        sendNetworkMessage(psm, wg, connection, &dsmStore[i],
                           &dsWriterIds[i], nmDsmCount);
    }

    /* Clean up DSM */
    for(size_t i = 0; i < dsmCount; i++) {
        UA_DataSetMessage_clear(&dsmStore[i]);
    }

    unlockServer(psm->sc.server);
}

/***********************/
/* Connection Handling */
/***********************/

static UA_StatusCode
UA_WriterGroup_connectMQTT(UA_PubSubManager *psm, UA_WriterGroup *wg,
                           UA_Boolean validate);

static UA_StatusCode
UA_WriterGroup_connectUDPUnicast(UA_PubSubManager *psm, UA_WriterGroup *wg,
                                 UA_Boolean validate);

typedef struct  {
    UA_String profileURI;
    UA_String protocol;
    UA_Boolean json;
    UA_StatusCode (*connectWriterGroup)(UA_PubSubManager *psm, UA_WriterGroup *wg,
                                        UA_Boolean validate);
} WriterGroupProfileMapping;

static WriterGroupProfileMapping writerGroupProfiles[UA_PUBSUB_PROFILES_SIZE] = {
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"),
     UA_STRING_STATIC("udp"), false, UA_WriterGroup_connectUDPUnicast},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp"),
     UA_STRING_STATIC("mqtt"), false, UA_WriterGroup_connectMQTT},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json"),
     UA_STRING_STATIC("mqtt"), true, UA_WriterGroup_connectMQTT},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"),
     UA_STRING_STATIC("eth"), false, NULL}
};

static void
WriterGroupChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                          void *application, void **connectionContext,
                          UA_ConnectionState state, const UA_KeyValueMap *params,
                          UA_ByteString msg) {
    if(!connectionContext)
        return;

    /* Get the context pointers */
    UA_WriterGroup *wg = (UA_WriterGroup*)*connectionContext;
    UA_PubSubManager *psm = (UA_PubSubManager*)application;
    UA_Server *server = psm->sc.server;

    lockServer(server);

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        if(wg->sendChannel == connectionId) {
            /* Reset the connection channel */
            wg->sendChannel = 0;

            /* PSC marked for deletion and the last EventLoop connection has closed */
            if(wg->deleteFlag) {
                UA_WriterGroup_remove(psm, wg);
                unlockServer(server);
                return;
            }
        }

        /* Reconnect automatically if the connection was operational. This sets
         * the connection state if connecting fails. Attention! If there are
         * several send or recv channels, then the connection is only reopened if
         * all of them close - which is usually the case. */
        if(wg->head.state == UA_PUBSUBSTATE_OPERATIONAL)
            UA_WriterGroup_connect(psm, wg, false);

        /* Switch the psm state from stopping to stopped once the last
         * connection has closed */
        UA_PubSubManager_setState(psm, psm->sc.state);

        unlockServer(server);
        return;
    }

    /* Store the connectionId (if a new connection) */
    if(wg->sendChannel && wg->sendChannel != connectionId) {
        UA_LOG_WARNING_PUBSUB(psm->logging, wg,
                              "WriterGroup is already bound to a different channel");
        unlockServer(server);
        return;
    }
    wg->sendChannel = connectionId;

    /* Connection open, set to operational if not already done */
    UA_WriterGroup_setPubSubState(psm, wg, wg->head.state);
    
    /* Send-channels don't receive messages */
    unlockServer(server);
}

static UA_StatusCode
UA_WriterGroup_connectUDPUnicast(UA_PubSubManager *psm, UA_WriterGroup *wg,
                                 UA_Boolean validate) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Already connected? */
    if(wg->sendChannel != 0 && !validate)
        return UA_STATUSCODE_GOOD;

    /* Check if address is available in TransportSettings */
    if(((wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_DECODED ||
         wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
        wg->config.transportSettings.content.decoded.type ==
        &UA_TYPES[UA_TYPES_DATAGRAMWRITERGROUPTRANSPORTDATATYPE]))
        return UA_STATUSCODE_GOOD;

    /* Unpack the TransportSettings */
    if((wg->config.transportSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
        wg->config.transportSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       wg->config.transportSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_DATAGRAMWRITERGROUPTRANSPORT2DATATYPE]) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "Invalid TransportSettings for a UDP Connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_DatagramWriterGroupTransport2DataType *ts =
        (UA_DatagramWriterGroupTransport2DataType*)
        wg->config.transportSettings.content.decoded.data;

    /* Unpack the address */
    if((ts->address.encoding != UA_EXTENSIONOBJECT_DECODED &&
        ts->address.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       ts->address.content.decoded.type != &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "Invalid TransportSettings Address for a UDP Connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType *)
        ts->address.content.decoded.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port;
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "Could not parse the UDP network URL");
        return res;
    }

    /* Set up the connection parameters */
    UA_Boolean listen = false;
    UA_KeyValuePair kvp[5];
    UA_KeyValueMap kvm = {4, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[1].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&kvp[2].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[3].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(!UA_String_isEmpty(&addressUrl->networkInterface)) {
        kvp[4].key = UA_QUALIFIEDNAME(0, "interface");
        UA_Variant_setScalar(&kvp[4].value, &addressUrl->networkInterface,
                             &UA_TYPES[UA_TYPES_STRING]);
        kvm.mapSize++;
    }

    /* Connect */
    UA_ConnectionManager *cm = wg->linkedConnection->cm;
    res = cm->openConnection(cm, &kvm, psm, wg, WriterGroupChannelCallback);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg, "Could not open a UDP send channel");
    }
    return res;
}

static UA_StatusCode
UA_WriterGroup_connectMQTT(UA_PubSubManager *psm, UA_WriterGroup *wg,
                           UA_Boolean validate) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PubSubConnection *c = wg->linkedConnection;
    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Get the TransportSettings */
    UA_ExtensionObject *ts = &wg->config.transportSettings;
    if((ts->encoding != UA_EXTENSIONOBJECT_DECODED &&
        ts->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       ts->content.decoded.type !=
       &UA_TYPES[UA_TYPES_BROKERWRITERGROUPTRANSPORTDATATYPE]) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg, "Wrong TransportSettings type for MQTT");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_BrokerWriterGroupTransportDataType *transportSettings =
        (UA_BrokerWriterGroupTransportDataType*)ts->content.decoded.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port = 1883; /* Default */
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "Could not parse the MQTT network URL");
        return res;
    }

    /* Set up the connection parameters.
     * TODO: Complete the MQTT parameters. */
    UA_Boolean listen = false;
    UA_KeyValuePair kvp[5];
    UA_KeyValueMap kvm = {5, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "subscribe");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[2].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "topic");
    UA_Variant_setScalar(&kvp[3].value, &transportSettings->queueName,
                         &UA_TYPES[UA_TYPES_STRING]);
    kvp[4].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[4].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* Connect */
    res = c->cm->openConnection(c->cm, &kvm, psm, wg, WriterGroupChannelCallback);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg, "Could not open the MQTT connection");
    }
    return res;
}

static void
UA_WriterGroup_disconnect(UA_WriterGroup *wg) {
    if(wg->sendChannel == 0)
        return;
    UA_PubSubConnection *c = wg->linkedConnection;
    if(!c || !c->cm)
        return;
    c->cm->closeConnection(c->cm, wg->sendChannel);
}

static UA_StatusCode
UA_WriterGroup_connect(UA_PubSubManager *psm, UA_WriterGroup *wg,
                       UA_Boolean validate) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Check if already connected or no WG TransportSettings */
    if(!UA_WriterGroup_canConnect(wg) && !validate)
        return UA_STATUSCODE_GOOD;

    /* Is this a WriterGroup with custom TransportSettings beyond the
     * PubSubConnection? */
    if(wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return UA_STATUSCODE_GOOD;

    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    if(!el) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg, "No EventLoop configured");
        UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_ERROR);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_PubSubConnection *c = wg->linkedConnection;
    if(!c)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Look up the connection manager for the connection */
    WriterGroupProfileMapping *profile = NULL;
    for(size_t i = 0; i < UA_PUBSUB_PROFILES_SIZE; i++) {
        if(!UA_String_equal(&c->config.transportProfileUri,
                            &writerGroupProfiles[i].profileURI))
            continue;
        profile = &writerGroupProfiles[i];
        break;
    }

    UA_ConnectionManager *cm = (profile) ? getCM(el, profile->protocol) : NULL;
    if(!cm || (c->cm && cm != c->cm)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c,
                            "The requested profile \"%S\"is not supported",
                            c->config.transportProfileUri);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    c->cm = cm;
    c->json = profile->json;

    /* Connect */
    return (profile->connectWriterGroup) ?
        profile->connectWriterGroup(psm, wg, validate) : UA_STATUSCODE_GOOD;
}

/**************/
/* Server API */
/**************/

UA_StatusCode
UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection,
                         const UA_WriterGroupConfig *writerGroupConfig,
                         UA_NodeId *writerGroupIdentifier) {
    if(!server || !writerGroupConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    if(!psm) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_StatusCode res = UA_WriterGroup_create(psm, connection, writerGroupConfig,
                                              writerGroupIdentifier);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroup);
    if(wg)
        UA_WriterGroup_remove(psm, wg);
    else
        res = UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_enableWriterGroup(UA_Server *server, const UA_NodeId writerGroup)  {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroup);
    UA_StatusCode res =
        (wg) ? UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_OPERATIONAL)
             :  UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_disableWriterGroup(UA_Server *server,
                             const UA_NodeId writerGroup) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroup);
    UA_StatusCode res =
        (wg) ? UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_DISABLED)
             :  UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
UA_Server_setWriterGroupActivateKey(UA_Server *server,
                                    const UA_NodeId writerGroup) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroup);
    if(wg) {
        if(wg->keyStorage && wg->keyStorage->currentItem) {
            res = UA_PubSubKeyStorage_activateKeyToChannelContext(
                psm, wg->head.identifier, wg->config.securityGroupId);
        } else {
            res = UA_STATUSCODE_BADINTERNALERROR;
        }
    }
    unlockServer(server);
    return res;
}
#endif

UA_StatusCode
UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup,
                               UA_WriterGroupConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroup);
    UA_StatusCode res = (wg) ?
        UA_WriterGroupConfig_copy(&wg->config, config) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getWriterGroupState(UA_Server *server, const UA_NodeId wgId,
                              UA_PubSubState *state) {
    if(!server || !state)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(getPSM(server), wgId);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(wg)
        *state = wg->head.state;
    else
        res = UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_triggerWriterGroupPublish(UA_Server *server,
                                    const UA_NodeId wgId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, wgId);
    if(!wg) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    unlockServer(server);
    UA_WriterGroup_publishCallback(psm, wg);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_getWriterGroupLastPublishTimestamp(UA_Server *server,
                                             const UA_NodeId wgId,
                                             UA_DateTime *timestamp) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(getPSM(server), wgId);
    if(!wg) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    *timestamp = wg->lastPublishTimeStamp;
    unlockServer(server);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup,
                                       UA_UInt32 securityTokenId,
                                       const UA_ByteString signingKey,
                                       const UA_ByteString encryptingKey,
                                       const UA_ByteString keyNonce) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroup);
    UA_StatusCode res =
        (wg) ? UA_WriterGroup_setEncryptionKeys(psm, wg, securityTokenId,
                                                 signingKey, encryptingKey, keyNonce)
              : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_updateWriterGroupConfig(UA_Server *server, const UA_NodeId wgId,
                                  const UA_WriterGroupConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, wgId);
    if(!wg) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    if(UA_PubSubState_isEnabled(wg->head.state)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "The WriterGroup must be disabled to update the config");
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Validate the new configuration */
    UA_StatusCode res = validateWriterGroupConfig(psm, &wg->head, config);
    if(res != UA_STATUSCODE_GOOD) {
        unlockServer(server);
        return res;
    }

    /* Store the old configuration */
    UA_WriterGroupConfig oldConfig = wg->config;
    memset(&wg->config, 0, sizeof(UA_WriterGroupConfig));

    /* Deep copy the new config */
    res = UA_WriterGroupConfig_copy(config, &wg->config);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Validate the connection settings */
    res = UA_WriterGroup_connect(psm, wg, true);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                            "Could not validate the connection parameters");
        goto errout;
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    if(!UA_String_equal(&wg->config.securityGroupId, &oldConfig.securityGroupId) ||
       wg->config.securityMode != oldConfig.securityMode) {
        /* Detach keystorage and reattach if needed */
        if(wg->keyStorage) {
            UA_PubSubKeyStorage_detachKeyStorage(psm, wg->keyStorage);
            wg->keyStorage = NULL;
        }
        if(wg->config.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
           wg->config.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
            res = writerGroupAttachSKSKeystorage(psm, wg);
            if(res != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR_PUBSUB(psm->logging, wg,
                                    "Attaching the SKS KeyStorage failed");
                goto errout;
            }
        }
    }
#endif

    /* Clean up and return */
    UA_WriterGroupConfig_clear(&oldConfig);
    unlockServer(server);
    return UA_STATUSCODE_GOOD;

 errout:
    UA_WriterGroupConfig_clear(&wg->config);
    wg->config = oldConfig; /* Restore the old config */
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_computeWriterGroupOffsetTable(UA_Server *server,
                                        const UA_NodeId writerGroupId,
                                        UA_PubSubOffsetTable *ot) {
    if(!server || !ot)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);

    /* Get the Writer Group */
    UA_PubSubManager *psm = getPSM(server);
    UA_WriterGroup *wg = (psm) ? UA_WriterGroup_find(psm, writerGroupId) : NULL;
    if(!wg) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Initialize variables so we can goto cleanup below */
    UA_DataSetField *field = NULL;
    UA_NetworkMessage networkMessage;
    memset(&networkMessage, 0, sizeof(networkMessage));
    memset(ot, 0, sizeof(UA_PubSubOffsetTable));

    /* Prepare the metadata encode the DataSetMessages */
    PubSubEncodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubEncodeCtx));
    ctx.ot = ot;

    size_t i = 0;
    UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, wg->writersCount);
    memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * wg->writersCount);
    ctx.eo.metaData = emd;
    ctx.eo.metaDataSize = wg->writersCount;
    UA_DataSetWriter *dsw;
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        emd[i].dataSetWriterId = dsw->config.dataSetWriterId;
        UA_PublishedDataSet *pds = dsw->connectedDataSet;
        if(pds) {
            emd[i].fields = pds->dataSetMetaData.fields;
            emd[i].fieldsSize = pds->dataSetMetaData.fieldsSize;
        }
        i++;
    }

    /* Validate the DataSetWriters and generate their DataSetMessage */
    size_t msgSize;
    size_t dsmCount = 0;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount);
    UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount);
    memset(dsmStore, 0, sizeof(UA_DataSetMessage) * wg->writersCount);
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
        res = UA_DataSetWriter_generateDataSetMessage(psm, dsw, &dsmStore[dsmCount]);
        dsmCount++;
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Generate the NetworkMessage */
    res = generateNetworkMessage(wg->linkedConnection, wg, dsmStore, dsWriterIds,
                                 (UA_Byte) dsmCount, &wg->config.messageSettings,
                                 &wg->config.transportSettings, &networkMessage);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Compute the message length and generate the old format offset-table (done
     * inside calcSizeBinary) */
    msgSize = UA_NetworkMessage_calcSizeBinaryInternal(&ctx, &networkMessage);
    if(msgSize == 0) {
        res = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Create the encoded network message */
    res = UA_NetworkMessage_encodeBinary(&networkMessage, &ot->networkMessage, &ctx.eo);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Pick up the component NodeIds */
    dsw = NULL;
    for(i = 0; i < ot->offsetsSize; i++) {
        UA_PubSubOffset *o = &ot->offsets[i];
        switch(o->offsetType) {
        case UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER:
        case UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_TIMESTAMP:
        case UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_PICOSECONDS:
        case UA_PUBSUBOFFSETTYPE_NETWORKMESSAGE_GROUPVERSION:
            res |= UA_NodeId_copy(&wg->head.identifier, &o->component);
            break;
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE:
            dsw = (dsw == NULL) ? LIST_FIRST(&wg->writers) : LIST_NEXT(dsw, listEntry);
            field = NULL;
            /* fall through */
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER:
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_STATUS:
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_TIMESTAMP:
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_PICOSECONDS:
            UA_assert(dsw);
            res |= UA_NodeId_copy(&dsw->head.identifier, &o->component);
            break;
        case UA_PUBSUBOFFSETTYPE_DATASETFIELD_DATAVALUE:
            UA_assert(dsw && dsw->connectedDataSet);
            field = (field == NULL) ?
                TAILQ_FIRST(&dsw->connectedDataSet->fields) : TAILQ_NEXT(field, listEntry);
            res |= UA_NodeId_copy(&field->identifier, &o->component);
            break;
        case UA_PUBSUBOFFSETTYPE_DATASETFIELD_VARIANT:
            UA_assert(dsw && dsw->connectedDataSet);
            field = (field == NULL) ?
                TAILQ_FIRST(&dsw->connectedDataSet->fields) : TAILQ_NEXT(field, listEntry);
            res |= UA_NodeId_copy(&field->identifier, &o->component);
            break;
        case UA_PUBSUBOFFSETTYPE_DATASETFIELD_RAW:
            UA_assert(dsw && dsw->connectedDataSet);
            field = (field == NULL) ?
                TAILQ_FIRST(&dsw->connectedDataSet->fields) : TAILQ_NEXT(field, listEntry);
            res |= UA_NodeId_copy(&field->identifier, &o->component);
            break;
        default:
            break;
        }
    }

    /* Clean up */
 cleanup:
    if(res != UA_STATUSCODE_GOOD)
        UA_PubSubOffsetTable_clear(ot);

    for(i = 0; i < dsmCount; i++) {
        UA_DataSetMessage_clear(&dsmStore[i]);
    }

    unlockServer(server);

    return res;
}

void
UA_PubSubOffsetTable_clear(UA_PubSubOffsetTable *ot) {
    for(size_t i = 0; i < ot->offsetsSize; i++) {
        UA_NodeId_clear(&ot->offsets[i].component);
    }
    UA_ByteString_clear(&ot->networkMessage);
    UA_free(ot->offsets);
    memset(ot, 0, sizeof(UA_PubSubOffsetTable));
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_reader.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2025 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */


static UA_Boolean
publisherIdIsMatching(UA_NetworkMessage *msg, UA_PublisherId *idB) {
    if(!msg->publisherIdEnabled)
        return true;
    UA_PublisherId *idA = &msg->publisherId;
    if(idA->idType != idB->idType)
        return false;
    switch(idA->idType) {
        case UA_PUBLISHERIDTYPE_BYTE:   return idA->id.byte == idB->id.byte;
        case UA_PUBLISHERIDTYPE_UINT16: return idA->id.uint16 == idB->id.uint16;
        case UA_PUBLISHERIDTYPE_UINT32: return idA->id.uint32 == idB->id.uint32;
        case UA_PUBLISHERIDTYPE_UINT64: return idA->id.uint64 == idB->id.uint64;
        case UA_PUBLISHERIDTYPE_STRING: return UA_String_equal(&idA->id.string, &idB->id.string);
        default: break;
    }
    return false;
}

#if UA_LOGLEVEL <= 200
static void
printPublisherId(char *out, size_t size, UA_PublisherId *id) {
    switch(id->idType) {
    case UA_PUBLISHERIDTYPE_BYTE:   mp_snprintf(out, size, "(b)%u", (unsigned)id->id.byte); break;
    case UA_PUBLISHERIDTYPE_UINT16: mp_snprintf(out, size, "(u16)%u", (unsigned)id->id.uint16); break;
    case UA_PUBLISHERIDTYPE_UINT32: mp_snprintf(out, size, "(u32)%u", (unsigned)id->id.uint32); break;
    case UA_PUBLISHERIDTYPE_UINT64: mp_snprintf(out, size, "(u64)%lu", id->id.uint64); break;
    case UA_PUBLISHERIDTYPE_STRING: mp_snprintf(out, size, "\"%S\"", id->id.string); break;
    default: out[0] = 0; break;
    }
}
#endif

UA_StatusCode
UA_DataSetReader_checkIdentifier(UA_PubSubManager *psm, UA_DataSetReader *dsr,
                                 UA_NetworkMessage *msg) {
    if(!publisherIdIsMatching(msg, &dsr->config.publisherId)) {
#if UA_LOGLEVEL <= 200
        char idAStr[512];
        char idBStr[512];
        printPublisherId(idAStr, 512, &dsr->config.publisherId);
        printPublisherId(idBStr, 512, &msg->publisherId);
        UA_LOG_DEBUG_PUBSUB(psm->logging, dsr, "PublisherId does not match. "
                            "Expected %s, received %s", idAStr, idBStr);
#endif
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_ReaderGroup *rg = dsr->linkedReaderGroup;
    if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) {
        // TODO
        /* if(dsr->config.dataSetWriterId == */
        /*    *msg->payloadHeader.dataSetPayloadHeader.dataSetWriterIds) { */
        /*     return UA_STATUSCODE_GOOD; */
        /* } */

        /* UA_LOG_DEBUG_PUBSUB(psm->logging, dsr, "DataSetWriterId does not match. " */
        /*                     "Expected %u, received %u", dsr->config.dataSetWriterId, */
        /*                     *msg->payloadHeader.dataSetPayloadHeader.dataSetWriterIds); */
        return UA_STATUSCODE_BADNOTFOUND;
    }

    if(msg->groupHeaderEnabled && msg->groupHeader.writerGroupIdEnabled) {
        if(dsr->config.writerGroupId != msg->groupHeader.writerGroupId) {
            UA_LOG_DEBUG_PUBSUB(psm->logging, dsr, "WriterGroupId does not match. "
                                "Expected %u, received %u", dsr->config.writerGroupId,
                                msg->groupHeader.writerGroupId);
            return UA_STATUSCODE_BADNOTFOUND;
        }
    }

    if(msg->payloadHeaderEnabled) {
        for(size_t i = 0; i < msg->messageCount; i++) {
            if(dsr->config.dataSetWriterId == msg->dataSetWriterIds[i])
                return UA_STATUSCODE_GOOD;
        }
        UA_LOG_DEBUG_PUBSUB(psm->logging, dsr,
                            "DataSetWriterIds in the payload do not match");
        return UA_STATUSCODE_BADNOTFOUND;
    }

    return UA_STATUSCODE_GOOD;
}

UA_DataSetReader *
UA_DataSetReader_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_PubSubConnection *psc;
    TAILQ_FOREACH(psc, &psm->connections, listEntry) {
        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &psc->readerGroups, listEntry) {
            UA_DataSetReader *dsr;
            LIST_FOREACH(dsr, &rg->readers, listEntry) {
                if(UA_NodeId_equal(&id, &dsr->head.identifier))
                    return dsr;
            }
        }
    }
    return NULL;
}

static UA_StatusCode
validateDSRConfig(UA_PubSubManager *psm, UA_DataSetReader *dsr) {
    /* Check if used dataSet metaData is valid in context of the rest of the config */
    if(dsr->config.dataSetFieldContentMask & UA_DATASETFIELDCONTENTMASK_RAWDATA) {
        for(size_t i = 0; i < dsr->config.dataSetMetaData.fieldsSize; i++) {
            const UA_FieldMetaData *field = &dsr->config.dataSetMetaData.fields[i];
            if((field->builtInType == UA_NS0ID_STRING || field->builtInType == UA_NS0ID_BYTESTRING) &&
               field->maxStringLength == 0) {
                /* Fields of type String or ByteString need to have defined
                 * MaxStringLength*/
                UA_LOG_ERROR_PUBSUB(psm->logging, dsr,
                                    "Add DataSetReader failed. MaxStringLength must be "
                                    "set in MetaData when using RawData field encoding.");
                return UA_STATUSCODE_BADCONFIGURATIONERROR;
            }

            /* Warn if the field is a structure type that contains
             * String/ByteString members. MaxStringLength padding is not
             * yet applied for strings nested inside structures. */
            const UA_DataType *type =
                UA_findDataTypeWithCustom(&field->dataType,
                                          psm->sc.server->config.customDataTypes);
            if(type &&
               (type->typeKind == UA_DATATYPEKIND_STRUCTURE ||
                type->typeKind == UA_DATATYPEKIND_UNION ||
                type->typeKind == UA_DATATYPEKIND_OPTSTRUCT) &&
               typeContainsString(type, 0)) {
                UA_LOG_WARNING_PUBSUB(psm->logging, dsr,
                                      "Field %.*s uses a structure type that "
                                      "contains String/ByteString members. "
                                      "MaxStringLength padding is not applied for "
                                      "strings inside structures with RawData encoding.",
                                      (int)field->name.length, field->name.data);
            }
        }
    }
    return UA_STATUSCODE_GOOD;
}

static void
disconnectDSR2Standalone(UA_PubSubManager *psm, UA_DataSetReader *dsr) {
    /* Check if a sds name is defined */
    const UA_String sdsName = dsr->config.linkedStandaloneSubscribedDataSetName;
    if(UA_String_isEmpty(&sdsName))
        return;

    UA_SubscribedDataSet *sds = UA_SubscribedDataSet_findByName(psm, sdsName);
    if(!sds)
        return;

    /* Remove the backpointer from the sds */
    sds->connectedReader = NULL;

    /* Remove the references in the information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    disconnectDataSetReaderToDataSet(psm->sc.server, dsr->head.identifier);
#endif
}

/* Connect to StandaloneSubscribedDataSet if a name is defined */
static UA_StatusCode
connectDSR2Standalone(UA_PubSubManager *psm, UA_DataSetReader *dsr) {
    /* Check if a sds name is defined */
    const UA_String sdsName = dsr->config.linkedStandaloneSubscribedDataSetName;
    if(UA_String_isEmpty(&sdsName))
        return UA_STATUSCODE_GOOD;

    UA_SubscribedDataSet *sds = UA_SubscribedDataSet_findByName(psm, sdsName);
    if(!sds)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Already connected? */
    if(sds->connectedReader) {
        if(sds->connectedReader != dsr)
            UA_LOG_ERROR_PUBSUB(psm->logging, dsr,
                                "Configured StandaloneSubscribedDataSet already "
                                "connected to a different DataSetReader");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check supported type */
    if(sds->config.subscribedDataSetType != UA_PUBSUB_SDS_TARGET) {
        UA_LOG_ERROR_PUBSUB(psm->logging, dsr,
                            "Not implemented! Currently only SubscribedDataSet as "
                            "TargetVariables is implemented");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    UA_LOG_DEBUG_PUBSUB(psm->logging, dsr, "Connecting SubscribedDataSet");

    /* Copy the metadata from the sds */
    UA_DataSetMetaDataType metaData;
    UA_StatusCode res = UA_DataSetMetaDataType_copy(&sds->config.dataSetMetaData, &metaData);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Prepare the input for _createTargetVariables and call it */
    UA_TargetVariablesDataType *tvs = &sds->config.subscribedDataSet.target;
    res = DataSetReader_createTargetVariables(psm, dsr, tvs->targetVariablesSize,
                                              tvs->targetVariables);
    if(res != UA_STATUSCODE_GOOD) {
        UA_DataSetMetaDataType_clear(&metaData);
        return res;
    }

    /* Use the metadata from the sds */
    UA_DataSetMetaDataType_clear(&dsr->config.dataSetMetaData);
    dsr->config.dataSetMetaData = metaData;

    /* Set the backpointer from the sds */
    sds->connectedReader = dsr;

    /* Make the connection visible in the information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    return connectDataSetReaderToDataSet(psm->sc.server, dsr->head.identifier,
                                         sds->head.identifier);
#else
    return UA_STATUSCODE_GOOD;
#endif
}

UA_StatusCode
UA_DataSetReader_create(UA_PubSubManager *psm, UA_NodeId readerGroupIdentifier,
                        const UA_DataSetReaderConfig *dataSetReaderConfig,
                        UA_NodeId *readerIdentifier) {
    if(!psm || !dataSetReaderConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Search the reader group by the given readerGroupIdentifier */
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupIdentifier);
    if(!rg)
        return UA_STATUSCODE_BADNOTFOUND;

    if(UA_PubSubState_isEnabled(rg->head.state)) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "Cannot add a DataSetReader while the "
                              "ReaderGroup is enabled");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* Allocate memory for new DataSetReader */
    UA_DataSetReader *dsr = (UA_DataSetReader *)
        UA_calloc(1, sizeof(UA_DataSetReader));
    if(!dsr)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    dsr->head.componentType = UA_PUBSUBCOMPONENT_DATASETREADER;
    dsr->linkedReaderGroup = rg;

    /* Add the new reader to the group. Add to the end of the linked list to
     * ensure the order for the realtime offsets is as expected. The received
     * DataSetMessages are matched via UA_DataSetReader_checkIdentifier for the
     * non-RT path. */
    UA_DataSetReader *after = LIST_FIRST(&rg->readers);
    if(!after) {
        LIST_INSERT_HEAD(&rg->readers, dsr, listEntry);
    } else {
        while(LIST_NEXT(after, listEntry))
            after = LIST_NEXT(after, listEntry);
        LIST_INSERT_AFTER(after, dsr, listEntry);
    }
    rg->readersCount++;

    /* Copy the config into the new dataSetReader */
    UA_StatusCode retVal =
        UA_DataSetReaderConfig_copy(dataSetReaderConfig, &dsr->config);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_DataSetReader_remove(psm, dsr);
        return retVal;
    }

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    retVal = addDataSetReaderRepresentation(psm->sc.server, dsr);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, rg,
                            "Adding the DataSetReader to the information model failed");
        UA_DataSetReader_remove(psm, dsr);
        return retVal;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(psm, &dsr->head.identifier);
#endif

    /* Cache the log string */
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%SDataSetReader %N\t| ",
                dsr->linkedReaderGroup->head.logIdString, dsr->head.identifier);
    dsr->head.logIdString = UA_STRING_ALLOC(tmpLogIdStr);

    /* Connect to StandaloneSubscribedDataSet if a name is defined. Needs to be
     * added in the information model first, as this adds references to the
     * StandaloneSubscribedDataSet. */
    retVal = connectDSR2Standalone(psm, dsr);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_DataSetReader_remove(psm, dsr);
        return retVal;
    }

    /* Validate the config */
    retVal = validateDSRConfig(psm, dsr);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_DataSetReader_remove(psm, dsr);
        return retVal;
    }

    /* Notify the application that a new Reader was created.
     * This may internally adjust the config */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        UA_StatusCode res = server->config.pubSubConfig.
            componentLifecycleCallback(server, dsr->head.identifier,
                                       UA_PUBSUBCOMPONENT_DATASETREADER, false);
        if(res != UA_STATUSCODE_GOOD) {
            UA_DataSetReader_remove(psm, dsr);
            return res;
        }
    }

    UA_LOG_INFO_PUBSUB(psm->logging, dsr, "DataSetReader created (State: %s)",
                       UA_PubSubState_name(dsr->head.state));

    if(readerIdentifier)
        UA_NodeId_copy(&dsr->head.identifier, readerIdentifier);

    /* Enable the DataSetReader immediately if the enabled flag is set */
    if(dataSetReaderConfig->enabled)
        UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_OPERATIONAL,
                                        UA_STATUSCODE_GOOD);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_DataSetReader_remove(UA_PubSubManager *psm, UA_DataSetReader *dsr) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_ReaderGroup *rg = dsr->linkedReaderGroup;
    UA_assert(rg);

    /* Check if the ReaderGroup is enabled */
    if(UA_PubSubState_isEnabled(rg->head.state)) {
        UA_LOG_WARNING_PUBSUB(psm->logging, dsr,
                              "Removal of the DataSetReader not possible while "
                              "the ReaderGroup is enabled");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check with the application if we can remove */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        UA_StatusCode res = server->config.pubSubConfig.
            componentLifecycleCallback(server, dsr->head.identifier,
                                       UA_PUBSUBCOMPONENT_DATASETREADER, true);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Disable and signal to the application */
    UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_DISABLED,
                                    UA_STATUSCODE_BADSHUTDOWN);

    /* Remove from information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(psm->sc.server, dsr->head.identifier, true);
#endif

    /* Check if a Standalone-SubscribedDataSet is associated with this reader
     * and disconnect it*/
    const UA_String sdsName = dsr->config.linkedStandaloneSubscribedDataSetName;
    UA_SubscribedDataSet *sds = (UA_String_isEmpty(&sdsName)) ?
        NULL : UA_SubscribedDataSet_findByName(psm, sdsName);
    if(sds && sds->connectedReader == dsr)
        sds->connectedReader = NULL;

    /* Remove DataSetReader from group */
    LIST_REMOVE(dsr, listEntry);
    rg->readersCount--;

    UA_LOG_INFO_PUBSUB(psm->logging, dsr, "DataSetReader deleted");

    UA_DataSetReaderConfig_clear(&dsr->config);
    UA_PubSubComponentHead_clear(&dsr->head);
    UA_free(dsr);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src,
                            UA_DataSetReaderConfig *dst) {
    memcpy(dst, src, sizeof(UA_DataSetReaderConfig));
    dst->writerGroupId = src->writerGroupId;
    dst->dataSetWriterId = src->dataSetWriterId;
    dst->dataSetFieldContentMask = src->dataSetFieldContentMask;
    dst->messageReceiveTimeout = src->messageReceiveTimeout;

    UA_StatusCode ret = UA_String_copy(&src->name, &dst->name);
    ret |= UA_PublisherId_copy(&src->publisherId, &dst->publisherId);
    ret |= UA_DataSetMetaDataType_copy(&src->dataSetMetaData, &dst->dataSetMetaData);
    ret |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
    ret |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
    ret |= UA_String_copy(&src->linkedStandaloneSubscribedDataSetName,
                             &dst->linkedStandaloneSubscribedDataSetName);

    if(src->subscribedDataSetType == UA_PUBSUB_SDS_TARGET) {
        ret |= UA_TargetVariablesDataType_copy(&src->subscribedDataSet.target,
                                               &dst->subscribedDataSet.target);
    }

    if(ret != UA_STATUSCODE_GOOD)
        UA_DataSetReaderConfig_clear(dst);

    return ret;
}

void
UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg) {
    UA_String_clear(&cfg->name);
    UA_String_clear(&cfg->linkedStandaloneSubscribedDataSetName);
    UA_PublisherId_clear(&cfg->publisherId);
    UA_DataSetMetaDataType_clear(&cfg->dataSetMetaData);
    UA_ExtensionObject_clear(&cfg->messageSettings);
    UA_ExtensionObject_clear(&cfg->transportSettings);
    if(cfg->subscribedDataSetType == UA_PUBSUB_SDS_TARGET) {
        UA_TargetVariablesDataType_clear(&cfg->subscribedDataSet.target);
    }
}

UA_StatusCode
UA_DataSetReader_setPubSubState(UA_PubSubManager *psm, UA_DataSetReader *dsr,
                                UA_PubSubState targetState, UA_StatusCode errorReason) {
    UA_ReaderGroup *rg = dsr->linkedReaderGroup;
    UA_assert(rg);

    /* Callback to modify the WriterGroup config and change the targetState
     * before the state machine executes */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.beforeStateChangeCallback) {
        server->config.pubSubConfig.
            beforeStateChangeCallback(server, dsr->head.identifier, &targetState);
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_PubSubState oldState = dsr->head.state;

    /* Custom state machine */
    if(dsr->config.customStateMachine) {
        res = dsr->config.customStateMachine(server, dsr->head.identifier,
                                             dsr->config.context,
                                             &dsr->head.state, targetState);
        if(res != UA_STATUSCODE_GOOD)
            errorReason = res;
        goto finalize_state_machine;
    }

    /* Internal state machine */
    switch(targetState) {
        /* Disabled */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        dsr->head.state = targetState;
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        if(rg->head.state == UA_PUBSUBSTATE_DISABLED ||
           rg->head.state == UA_PUBSUBSTATE_ERROR ||
           rg->head.state == UA_PUBSUBSTATE_PAUSED) {
            dsr->head.state = UA_PUBSUBSTATE_PAUSED; /* RG is disabled -> paused */
        } else {
            dsr->head.state = rg->head.state; /* RG is enabled -> same state */
        }
        break;

    default:
        dsr->head.state = UA_PUBSUBSTATE_ERROR;
        res = UA_STATUSCODE_BADINTERNALERROR;
        errorReason = res;
        break;
    }

    /* Only keep the timeout callback if the reader is operational */
    if(dsr->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
       dsr->msgRcvTimeoutTimerId != 0) {
        UA_EventLoop *el = psm->sc.server->config.eventLoop;
        el->removeTimer(el, dsr->msgRcvTimeoutTimerId);
        dsr->msgRcvTimeoutTimerId = 0;
    }

 finalize_state_machine:

    /* No state change has happened */
    if(dsr->head.state == oldState)
        return res;

    UA_LOG_INFO_PUBSUB(psm->logging, dsr, "%s -> %s",
                       UA_PubSubState_name(oldState),
                       UA_PubSubState_name(dsr->head.state));

    /* Inform application about state change */
    if(server->config.pubSubConfig.stateChangeCallback)
        server->config.pubSubConfig.
            stateChangeCallback(server, dsr->head.identifier,
                                dsr->head.state, errorReason);
                                
    return res;
}

/* This Method is used to initially set the SubscribedDataSet to
 * TargetVariablesType and to create the list of target Variables of a
 * SubscribedDataSetType. */
UA_StatusCode
DataSetReader_createTargetVariables(UA_PubSubManager *psm, UA_DataSetReader *dsr,
                                    size_t tvsSize, const UA_FieldTargetDataType *tvs) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    if(UA_PubSubState_isEnabled(dsr->head.state)) {
        UA_LOG_WARNING_PUBSUB(psm->logging, dsr,
                              "Cannot create Target Variables failed while "
                              "the DataSetReader is enabled");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    UA_TargetVariablesDataType newVars;
    UA_TargetVariablesDataType tmp = {tvsSize, (UA_FieldTargetDataType*)(uintptr_t)tvs};
    UA_StatusCode res = UA_TargetVariablesDataType_copy(&tmp, &newVars);   
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_TargetVariablesDataType_clear(&dsr->config.subscribedDataSet.target);
    dsr->config.subscribedDataSet.target = newVars;
    return UA_STATUSCODE_GOOD;
}

static void
UA_DataSetReader_handleMessageReceiveTimeout(UA_PubSubManager *psm,
                                             UA_DataSetReader *dsr) {
    UA_assert(dsr->head.componentType == UA_PUBSUBCOMPONENT_DATASETREADER);

    /* Don't signal an error if we don't expect messages to arrive */
    if(dsr->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
       dsr->head.state != UA_PUBSUBSTATE_PREOPERATIONAL)
        return;

    UA_LOG_DEBUG_PUBSUB(psm->logging, dsr, "Message receive timeout occurred");

    lockServer(psm->sc.server);
    UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_ERROR,
                                    UA_STATUSCODE_BADTIMEOUT);
    unlockServer(psm->sc.server);
}

void
UA_DataSetReader_process(UA_PubSubManager *psm, UA_DataSetReader *dsr,
                         UA_DataSetMessage *msg) {
    if(!dsr || !msg || !psm)
        return;

    UA_LOG_DEBUG_PUBSUB(psm->logging, dsr, "Received a network message");

    /* Received a (first) message for the Reader.
     * Transition from PreOperational to Operational. */
    if(dsr->head.state == UA_PUBSUBSTATE_PREOPERATIONAL)
        UA_DataSetReader_setPubSubState(psm, dsr, dsr->head.state, UA_STATUSCODE_GOOD);

    if(dsr->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
       dsr->head.state != UA_PUBSUBSTATE_PREOPERATIONAL) {
        UA_LOG_WARNING_PUBSUB(psm->logging, dsr,
                              "Received a network message but not operational");
        return;
    }

    if(!msg->header.dataSetMessageValid) {
        UA_LOG_INFO_PUBSUB(psm->logging, dsr,
                           "DataSetMessage is discarded: message is not valid");
        return;
    }

    /* TODO: Check ConfigurationVersion */
    /* if(msg->header.configVersionMajorVersionEnabled) {
     *     if(msg->header.configVersionMajorVersion !=
     *            dsr->config.dataSetMetaData.configurationVersion.majorVersion) {
     *         UA_LOG_WARNING(psm->logging, UA_LOGCATEGORY_SERVER,
     *                        "DataSetMessage is discarded: ConfigurationVersion "
     *                        "MajorVersion does not match");
     *         return;
     *     }
     * } */

    if(msg->header.dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME) {
        UA_LOG_WARNING_PUBSUB(psm->logging, dsr,
                              "DataSetMessage is discarded: Only keyframes are supported");
        return;
    }

    /* Configure / Update the timeout callback */
    if(dsr->config.messageReceiveTimeout > 0.0) {
        UA_EventLoop *el = psm->sc.server->config.eventLoop;
        if(dsr->msgRcvTimeoutTimerId == 0) {
            el->addTimer(el, (UA_Callback)UA_DataSetReader_handleMessageReceiveTimeout,
                         psm, dsr, dsr->config.messageReceiveTimeout, NULL,
                         UA_TIMERPOLICY_CURRENTTIME, &dsr->msgRcvTimeoutTimerId);
        } else {
            /* Reset the next execution time to now + interval */
            el->modifyTimer(el, dsr->msgRcvTimeoutTimerId,
                            dsr->config.messageReceiveTimeout, NULL,
                            UA_TIMERPOLICY_CURRENTTIME);
        }
    }

    /* Received a heartbeat with no fields */
    if(msg->fieldCount == 0)
        return;

    /* Check whether the field count matches the configuration */
    UA_TargetVariablesDataType *tvs = &dsr->config.subscribedDataSet.target;
    if(tvs->targetVariablesSize != msg->fieldCount) {
        UA_LOG_WARNING_PUBSUB(psm->logging, dsr,
                              "Number of fields does not match the "
                              "TargetVariables configuration");
        return;
    }

    /* Write the message fields. RT has the external data value configured. */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < msg->fieldCount; i++) {
        UA_FieldTargetDataType *tv = &tvs->targetVariables[i];
        UA_DataValue *field = &msg->data.keyFrameFields[i];
        if(!field->hasValue)
            continue;

        /* Write via the Write-Service */
        UA_WriteValue writeVal;
        UA_WriteValue_init(&writeVal);
        writeVal.attributeId = tv->attributeId;
        writeVal.indexRange = tv->receiverIndexRange;
        writeVal.nodeId = tv->targetNodeId;
        writeVal.value = *field;
        Operation_Write(psm->sc.server, &psm->sc.server->adminSession, &writeVal, &res);
        if(res != UA_STATUSCODE_GOOD)
            UA_LOG_INFO_PUBSUB(psm->logging, dsr,
                               "Error writing KeyFrame field %u: %s",
                               (unsigned)i, UA_StatusCode_name(res));
    }
}

/**************/
/* Server API */
/**************/

UA_StatusCode
UA_Server_addDataSetReader(UA_Server *server, UA_NodeId readerGroupId,
                           const UA_DataSetReaderConfig *config,
                           UA_NodeId *dsrId) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode res =
        UA_DataSetReader_create(getPSM(server), readerGroupId, config, dsrId);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removeDataSetReader(UA_Server *server, const UA_NodeId readerId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, readerId);
    UA_StatusCode res = (dsr) ?
        UA_DataSetReader_remove(psm, dsr) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getDataSetReaderConfig(UA_Server *server, const UA_NodeId dsrId,
                                 UA_DataSetReaderConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dsrId);
    UA_StatusCode res = (dsr) ?
        UA_DataSetReaderConfig_copy(&dsr->config, config) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getDataSetReaderState(UA_Server *server, const UA_NodeId dsrId,
                                UA_PubSubState *state) {
    if(!server || !state)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(getPSM(server), dsrId);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(dsr) {
        res = UA_STATUSCODE_GOOD;
        *state = dsr->head.state;
    }
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_enableDataSetReader(UA_Server *server, const UA_NodeId dsrId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dsrId);
    if(dsr)
        UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_OPERATIONAL,
                                        UA_STATUSCODE_GOOD);
    else
        ret = UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return ret;
}

UA_StatusCode
UA_Server_disableDataSetReader(UA_Server *server, const UA_NodeId dsrId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dsrId);
    if(dsr)
        UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_DISABLED,
                                        UA_STATUSCODE_GOOD);
    else
        ret = UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return ret;
}

UA_StatusCode
UA_Server_setDataSetReaderTargetVariables(UA_Server *server, const UA_NodeId dsrId,
                                          size_t targetVariablesSize,
                                          const UA_FieldTargetDataType *targetVariables) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dsrId);
    UA_StatusCode res = (dsr) ?
        DataSetReader_createTargetVariables(psm, dsr, targetVariablesSize,
                                            targetVariables) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_updateDataSetReaderConfig(UA_Server *server, const UA_NodeId dsrId,
                                    const UA_DataSetReaderConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dsrId);
    if(!dsr) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    if(UA_PubSubState_isEnabled(dsr->head.state)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, dsr,
                            "The DataSetReader must be disabled to update the config");
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Store the old config */
    UA_DataSetReaderConfig oldConfig = dsr->config;

    /* Copy the config into the new dataSetReader */
    UA_StatusCode retVal = UA_DataSetReaderConfig_copy(config, &dsr->config);
    if(retVal != UA_STATUSCODE_GOOD)
        goto errout;

    /* Change the connection to a StandaloneSubscribedDataSet */
    if(!UA_String_equal(&dsr->config.linkedStandaloneSubscribedDataSetName,
                        &oldConfig.linkedStandaloneSubscribedDataSetName)) {
        disconnectDSR2Standalone(psm, dsr);
        retVal = connectDSR2Standalone(psm, dsr);
        if(retVal != UA_STATUSCODE_GOOD)
            goto errout;
    }

    /* Validate the new config */
    retVal = validateDSRConfig(psm, dsr);
    if(retVal != UA_STATUSCODE_GOOD)
        goto errout;

    /* Clean up and return */
    UA_DataSetReaderConfig_clear(&oldConfig);
    unlockServer(server);
    return UA_STATUSCODE_GOOD;

    /* Fall back to the old config */
 errout:
    UA_DataSetReaderConfig_clear(&dsr->config);
    dsr->config = oldConfig;
    unlockServer(server);
    return retVal;
}

/**********************/
/* Offset Computation */
/**********************/

static UA_StatusCode
UA_PubSubDataSetReader_generateKeyFrameMessage(UA_Server *server,
                                               UA_DataSetMessage *dsm,
                                               UA_DataSetReader *dsr) {
    /* Prepare DataSetMessageContent */
    UA_TargetVariablesDataType *tv = &dsr->config.subscribedDataSet.target;
    UA_DataSetMetaDataType *metaData = &dsr->config.dataSetMetaData;
    if(tv->targetVariablesSize != metaData->fieldsSize)
        metaData = NULL;
    dsm->header.dataSetMessageValid = true;
    dsm->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
    dsm->fieldCount = (UA_UInt16) tv->targetVariablesSize;
    dsm->data.keyFrameFields = (UA_DataValue *)
            UA_Array_new(tv->targetVariablesSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
    if(!dsm->data.keyFrameFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;

     for(size_t counter = 0; counter < tv->targetVariablesSize; counter++) {
        /* Read the value and set the source in the reader config */
        UA_DataValue *dfv = &dsm->data.keyFrameFields[counter];
        UA_FieldTargetDataType *ftv = &tv->targetVariables[counter];

        /* Synthesize the field value from the FieldMetaData. This allows us to
         * prevent a read from the information model during startup. */
        UA_FieldMetaData *fieldMetaData = (metaData) ? &metaData->fields[counter] : NULL;
        if(fieldMetaData && fieldMetaData->valueRank == UA_VALUERANK_SCALAR) {
            const UA_DataType *type =
                UA_findDataTypeWithCustom(&fieldMetaData->dataType,
                                          server->config.customDataTypes);
            if(type == &UA_TYPES[UA_TYPES_STRING] && fieldMetaData->maxStringLength > 0) {
                UA_String *s = UA_String_new();
                if(!s) {
                    UA_DataSetMessage_clear(dsm);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                s->data = (UA_Byte*)
                    UA_calloc(fieldMetaData->maxStringLength, sizeof(UA_Byte));
                if(!s->data) {
                    UA_free(s);
                    UA_DataSetMessage_clear(dsm);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                s->length = fieldMetaData->maxStringLength;
                UA_Variant_setScalar(&dfv->value, s, type);
                dfv->hasValue = true;
            } else if(type && type->memSize < 512) {
                char buf[512];
                UA_init(buf, type);
                UA_StatusCode res = UA_Variant_setScalarCopy(&dfv->value, buf, type);
                if(res != UA_STATUSCODE_GOOD) {
                    UA_DataSetMessage_clear(dsm);
                    return res;
                }
                dfv->hasValue = true;
            }
        }

        /* Read the value from the information model */
        if(!dfv->hasValue) {
            UA_ReadValueId rvi;
            UA_ReadValueId_init(&rvi);
            rvi.nodeId = ftv->targetNodeId;
            rvi.attributeId = ftv->attributeId;
            rvi.indexRange = ftv->writeIndexRange;
            *dfv = readWithSession(server, &server->adminSession, &rvi,
                                   UA_TIMESTAMPSTORETURN_NEITHER);
        }

        /* Deactivate statuscode? */
        if(((u64)dsr->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
            dfv->hasStatus = false;

        /* Deactivate timestamps */
        if(((u64)dsr->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
            dfv->hasSourceTimestamp = false;
        if(((u64)dsr->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
            dfv->hasSourcePicoseconds = false;
        if(((u64)dsr->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
            dfv->hasServerTimestamp = false;
        if(((u64)dsr->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
            dfv->hasServerPicoseconds = false;
    }

    return UA_STATUSCODE_GOOD;
}

/* Generate a DataSetMessage for the given reader. */
UA_StatusCode
UA_DataSetReader_generateDataSetMessage(UA_Server *server,
                                        UA_DataSetMessage *dsm,
                                        UA_DataSetReader *dsr) {
    /* Support only for UADP configuration
     * TODO: JSON encoding if UA_DataSetReader_generateDataSetMessage used other
     * that RT configuration */

    UA_ExtensionObject *settings = &dsr->config.messageSettings;
    if(settings->content.decoded.type != &UA_TYPES[UA_TYPES_UADPDATASETREADERMESSAGEDATATYPE])
        return UA_STATUSCODE_BADNOTSUPPORTED;

    /* The configuration Flags are included inside the std. defined
     * UA_UadpDataSetReaderMessageDataType */
    UA_UadpDataSetReaderMessageDataType defaultUadpConfiguration;
    UA_UadpDataSetReaderMessageDataType *dsrMessageDataType =
        (UA_UadpDataSetReaderMessageDataType*) settings->content.decoded.data;

    if(!(settings->encoding == UA_EXTENSIONOBJECT_DECODED ||
         settings->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       !dsrMessageDataType->dataSetMessageContentMask) {
        /* Create default flag configuration if no dataSetMessageContentMask or
         * even messageSettings in UadpDataSetWriterMessageDataType was
         * passed. */
        memset(&defaultUadpConfiguration, 0, sizeof(UA_UadpDataSetReaderMessageDataType));
        defaultUadpConfiguration.dataSetMessageContentMask = (UA_UadpDataSetMessageContentMask)
            ((u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP |
             (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION |
             (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION);
        dsrMessageDataType = &defaultUadpConfiguration;
    }

    /* The field encoding depends on the flags inside the reader config. */
    if(dsr->config.dataSetFieldContentMask & (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA) {
        dsm->header.fieldEncoding = UA_FIELDENCODING_RAWDATA;
    } else if((u64)dsr->config.dataSetFieldContentMask &
              ((u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP |
               (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS |
               (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS |
               (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE)) {
        dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
    } else {
        dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
    }

    /* Std: 'The DataSetMessageContentMask defines the flags for the content
     * of the DataSetMessage header.' */
    if((u64)dsrMessageDataType->dataSetMessageContentMask &
       (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION) {
        dsm->header.configVersionMajorVersionEnabled = true;
        dsm->header.configVersionMajorVersion =
            dsr->config.dataSetMetaData.configurationVersion.majorVersion;
    }

    if((u64)dsrMessageDataType->dataSetMessageContentMask &
       (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION) {
        dsm->header.configVersionMinorVersionEnabled = true;
        dsm->header.configVersionMinorVersion =
            dsr->config.dataSetMetaData.configurationVersion.minorVersion;
    }

    if((u64)dsrMessageDataType->dataSetMessageContentMask &
       (u64)UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
        /* Will be modified when subscriber receives new nw msg */
        dsm->header.dataSetMessageSequenceNrEnabled = true;
        dsm->header.dataSetMessageSequenceNr = 1;
    }

    if((u64)dsrMessageDataType->dataSetMessageContentMask &
       (u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) {
        dsm->header.timestampEnabled = true;
        dsm->header.timestamp = UA_DateTime_now();
    }

    if((u64)dsrMessageDataType->dataSetMessageContentMask &
       (u64)UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS)
        dsm->header.picoSecondsIncluded = false;

    if((u64)dsrMessageDataType->dataSetMessageContentMask &
       (u64)UA_UADPDATASETMESSAGECONTENTMASK_STATUS)
        dsm->header.statusEnabled = true;

    /* Not supported for Delta frames atm */
    return UA_PubSubDataSetReader_generateKeyFrameMessage(server, dsm, dsr);
}


UA_StatusCode
UA_Server_computeDataSetReaderOffsetTable(UA_Server *server,
                                          const UA_NodeId dataSetReaderId,
                                          UA_PubSubOffsetTable *ot) {
    /* Validate the arguments */
    if(!server || !ot)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);

    /* Get the DataSetReader */
    UA_PubSubManager *psm = getPSM(server);
    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dataSetReaderId);
    if(!dsr) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Generate the DataSetMessage */
    UA_DataSetMessage dsm;
    memset(&dsm, 0, sizeof(UA_DataSetMessage));
    UA_StatusCode res = UA_DataSetReader_generateDataSetMessage(server, &dsm, dsr);
    if(res != UA_STATUSCODE_GOOD) {
        unlockServer(server);
        return res;
    }

    /* Reset the OffsetTable */
    memset(ot, 0, sizeof(UA_PubSubOffsetTable));

    /* Prepare the encoding context */
    UA_DataSetMessage_EncodingMetaData emd;
    memset(&emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData));
    emd.dataSetWriterId = dsr->config.dataSetWriterId;
    emd.fields = dsr->config.dataSetMetaData.fields;
    emd.fieldsSize = dsr->config.dataSetMetaData.fieldsSize;

    PubSubEncodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubEncodeCtx));
    ctx.ot = ot;
    ctx.eo.metaData = &emd;
    ctx.eo.metaDataSize = 1;

    /* Compute the offset */
    size_t fieldindex = 0;
    UA_FieldTargetDataType *tv = NULL;
    size_t msgSize = UA_DataSetMessage_calcSizeBinary(&ctx, &emd, &dsm, 0);
    if(msgSize == 0) {
        res = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Allocate the message */
    res = UA_ByteString_allocBuffer(&ot->networkMessage, msgSize);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Create the ByteString of the encoded DataSetMessage */
    ctx.ctx.pos = ot->networkMessage.data;
    ctx.ctx.end = ot->networkMessage.data + ot->networkMessage.length;
    res = UA_DataSetMessage_encodeBinary(&ctx, &emd, &dsm);
    if(res != UA_STATUSCODE_GOOD)
        goto errout;

    /* Pick up the component NodeIds */
    for(size_t i = 0; i < ot->offsetsSize; i++) {
        UA_PubSubOffset *o = &ot->offsets[i];
        switch(o->offsetType) {
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER:
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_STATUS:
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_TIMESTAMP:
        case UA_PUBSUBOFFSETTYPE_DATASETMESSAGE_PICOSECONDS:
            res |= UA_NodeId_copy(&dsr->head.identifier, &o->component);
            break;
        case UA_PUBSUBOFFSETTYPE_DATASETFIELD_DATAVALUE:
            tv = &dsr->config.subscribedDataSet.target.targetVariables[fieldindex];
            res |= UA_NodeId_copy(&tv->targetNodeId, &o->component);
            fieldindex++;
            break;
        case UA_PUBSUBOFFSETTYPE_DATASETFIELD_VARIANT:
            tv = &dsr->config.subscribedDataSet.target.targetVariables[fieldindex];
            res |= UA_NodeId_copy(&tv->targetNodeId, &o->component);
            fieldindex++;
            break;
        case UA_PUBSUBOFFSETTYPE_DATASETFIELD_RAW:
            tv = &dsr->config.subscribedDataSet.target.targetVariables[fieldindex];
            res |= UA_NodeId_copy(&tv->targetNodeId, &o->component);
            fieldindex++;
            break;
        default:
            res = UA_STATUSCODE_BADINTERNALERROR;
            break;
        }
    }

    /* Clean up */
 errout:
    UA_DataSetMessage_clear(&dsm);
    if(res != UA_STATUSCODE_GOOD)
        UA_PubSubOffsetTable_clear(ot);
    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_readergroup.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2025 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

#ifdef UA_ENABLE_PUBSUB_SKS
#endif

UA_ReaderGroup *
UA_ReaderGroup_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_PubSubConnection *psc;
    TAILQ_FOREACH(psc, &psm->connections, listEntry) {
        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &psc->readerGroups, listEntry) {
            if(UA_NodeId_equal(&id, &rg->head.identifier))
                return rg;
        }
    }
    return NULL;
}

/* ReaderGroup Config Handling */

UA_StatusCode
UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src,
                          UA_ReaderGroupConfig *dst) {
    memcpy(dst, src, sizeof(UA_ReaderGroupConfig));
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_String_copy(&src->name, &dst->name);
    res |= UA_KeyValueMap_copy(&src->groupProperties, &dst->groupProperties);
    res |= UA_String_copy(&src->securityGroupId, &dst->securityGroupId);
    res |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
    if(res != UA_STATUSCODE_GOOD)
        UA_ReaderGroupConfig_clear(dst);
    return res;
}

void
UA_ReaderGroupConfig_clear(UA_ReaderGroupConfig *readerGroupConfig) {
    UA_String_clear(&readerGroupConfig->name);
    UA_KeyValueMap_clear(&readerGroupConfig->groupProperties);
    UA_String_clear(&readerGroupConfig->securityGroupId);
    UA_ExtensionObject_clear(&readerGroupConfig->transportSettings);
}


#ifdef UA_ENABLE_PUBSUB_SKS
static UA_StatusCode
readerGroupAttachSKSKeystorage(UA_PubSubManager *psm, UA_ReaderGroup *rg) {
    /* No SecurityGroup defined */
    if(UA_String_isEmpty(&rg->config.securityGroupId) || !rg->config.securityPolicy)
        return UA_STATUSCODE_GOOD;

    /* KeyStorage already connected */
    if(rg->keyStorage)
        return UA_STATUSCODE_GOOD;

    /* Does the key storage already exist? */
    rg->keyStorage = UA_PubSubKeyStorage_find(psm, rg->config.securityGroupId);
    if(rg->keyStorage) {
        rg->keyStorage->referenceCount++; /* Increase the ref count */
        return UA_STATUSCODE_GOOD;
    }

    /* Create a new key storage */
    rg->keyStorage = (UA_PubSubKeyStorage *)UA_calloc(1, sizeof(UA_PubSubKeyStorage));
    if(!rg->keyStorage)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Initialize the KeyStorage */
    UA_StatusCode res =
        UA_PubSubKeyStorage_init(psm, rg->keyStorage, &rg->config.securityGroupId,
                                 rg->config.securityPolicy, 0, 0);
    if(res != UA_STATUSCODE_GOOD) {
        UA_PubSubKeyStorage_delete(psm, rg->keyStorage);
        rg->keyStorage = NULL;
        return res;
    }

    /* Increase the ref count */
    rg->keyStorage->referenceCount++;
    return UA_STATUSCODE_GOOD;
}
#endif

UA_StatusCode
UA_ReaderGroup_create(UA_PubSubManager *psm, UA_NodeId connectionId,
                      const UA_ReaderGroupConfig *rgc,
                      UA_NodeId *readerGroupId) {
    /* Check for valid readergroup configuration */
    if(!psm || !rgc)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Search the connection by the given connectionIdentifier */
    UA_PubSubConnection *c = UA_PubSubConnection_find(psm, connectionId);
    if(!c)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Allocate memory for new reader group and add settings */
    UA_ReaderGroup *newGroup = (UA_ReaderGroup *)UA_calloc(1, sizeof(UA_ReaderGroup));
    if(!newGroup)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    newGroup->head.componentType = UA_PUBSUBCOMPONENT_READERGROUP;
    newGroup->linkedConnection = c;

    /* Deep copy of the config */
    UA_StatusCode retval = UA_ReaderGroupConfig_copy(rgc, &newGroup->config);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newGroup);
        return retval;
    }

    /* Add to the connection */
    LIST_INSERT_HEAD(&c->readerGroups, newGroup, listEntry);
    c->readerGroupsSize++;

    /* Cache the log string */
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%SReaderGroup %N\t| ",
                c->head.logIdString, newGroup->head.identifier);
    newGroup->head.logIdString = UA_STRING_ALLOC(tmpLogIdStr);

    /* Validate the connection settings */
    retval = UA_ReaderGroup_connect(psm, newGroup, true);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, newGroup,
                            "Could not validate the connection parameters");
        UA_ReaderGroup_remove(psm, newGroup);
        return retval;
    }

    /* Attach SKS Keystorage */
#ifdef UA_ENABLE_PUBSUB_SKS
    if(rgc->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       rgc->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        retval = readerGroupAttachSKSKeystorage(psm, newGroup);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_PUBSUB(psm->logging, newGroup,
                                "Attaching the SKS KeyStorage failed");
            UA_ReaderGroup_remove(psm, newGroup);
            return retval;
        }
    }
#endif

    /* Create information model representation */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    retval |= addReaderGroupRepresentation(psm->sc.server, newGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ReaderGroup_remove(psm, newGroup);
        return retval;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(psm, &newGroup->head.identifier);
#endif

    /* Notify the application that a new ReaderGroup was created.
     * This may internally adjust the config */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        retval = server->config.pubSubConfig.
            componentLifecycleCallback(server, newGroup->head.identifier,
                                       UA_PUBSUBCOMPONENT_READERGROUP, false);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_ReaderGroup_remove(psm, newGroup);
            return retval;
        }
    }

    UA_LOG_INFO_PUBSUB(psm->logging, newGroup, "ReaderGroup created (State: %s)",
                   UA_PubSubState_name(newGroup->head.state));

    /* Trigger the connection state machine. It might open a socket only when
     * the first ReaderGroup is attached. */
    if(rgc->enabled)
        UA_PubSubConnection_setPubSubState(psm, c, c->head.state);

    /* Copying a numeric NodeId always succeeds */
    if(readerGroupId)
        UA_NodeId_copy(&newGroup->head.identifier, readerGroupId);

    /* Enable the ReaderGroup immediately if the enabled flag is set */
    if(rgc->enabled)
        UA_ReaderGroup_setPubSubState(psm, newGroup, UA_PUBSUBSTATE_OPERATIONAL);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ReaderGroup_remove(UA_PubSubManager *psm, UA_ReaderGroup *rg) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PubSubConnection *connection = rg->linkedConnection;
    UA_assert(connection);

    /* Check with the application if we can remove */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.componentLifecycleCallback) {
        UA_StatusCode res = server->config.pubSubConfig.
            componentLifecycleCallback(server, rg->head.identifier,
                                       UA_PUBSUBCOMPONENT_READERGROUP, true);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Disable (and disconnect) and set the deleteFlag. This prevents a
     * reconnect and triggers the deletion when the last open socket is
     * closed. */
    rg->deleteFlag = true;
    UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED);

    UA_DataSetReader *dsr, *tmp_dsr;
    LIST_FOREACH_SAFE(dsr, &rg->readers, listEntry, tmp_dsr) {
        UA_DataSetReader_remove(psm, dsr);
    }

    if(rg->config.securityPolicy && rg->securityPolicyContext) {
        UA_PubSubSecurityPolicy *sp = rg->config.securityPolicy;
        sp->deleteGroupContext(sp, rg->securityPolicyContext);
        rg->securityPolicyContext = NULL;
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    if(rg->keyStorage) {
        UA_PubSubKeyStorage_detachKeyStorage(psm, rg->keyStorage);
        rg->keyStorage = NULL;
    }
#endif

    if(rg->recvChannelsSize == 0) {
        /* Unlink from the connection */
        LIST_REMOVE(rg, listEntry);
        connection->readerGroupsSize--;
        rg->linkedConnection = NULL;

        /* Actually remove the ReaderGroup */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
        deleteNode(psm->sc.server, rg->head.identifier, true);
#endif

        UA_LOG_INFO_PUBSUB(psm->logging, rg, "ReaderGroup deleted");

        UA_ReaderGroupConfig_clear(&rg->config);
        UA_PubSubComponentHead_clear(&rg->head);
        UA_free(rg);
    }

    /* Update the connection state */
    UA_PubSubConnection_setPubSubState(psm, connection, connection->head.state);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ReaderGroup_setPubSubState(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                              UA_PubSubState targetState) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    if(rg->deleteFlag && targetState != UA_PUBSUBSTATE_DISABLED) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "The ReaderGroup is being deleted. Can only be disabled.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Callback to modify the WriterGroup config and change the targetState
     * before the state machine executes */
    UA_Server *server = psm->sc.server;
    if(server->config.pubSubConfig.beforeStateChangeCallback) {
        server->config.pubSubConfig.
            beforeStateChangeCallback(server, rg->head.identifier, &targetState);
    }

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubState oldState = rg->head.state;
    UA_PubSubConnection *connection = rg->linkedConnection;

    /* Are we doing a top-level state update or recursively? */
    UA_Boolean isTransient = rg->head.transientState;
    rg->head.transientState = true;

    /* Custom state machine */
    if(rg->config.customStateMachine) {
        ret = rg->config.customStateMachine(server, rg->head.identifier, rg->config.context,
                                            &rg->head.state, targetState);
        goto finalize_state_machine;
    }

    /* Internal state machine */
    switch(targetState) {
        /* Disabled or Error */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        rg->head.state = targetState;
        UA_ReaderGroup_disconnect(rg);
        rg->hasReceived = false;
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        if(psm->sc.state != UA_LIFECYCLESTATE_STARTED) {
            /* Avoid repeat warnings */
            if(oldState != UA_PUBSUBSTATE_PAUSED) {
                UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                                      "Cannot enable the ReaderGroup while the "
                                      "server is not running -> Paused State");
            }
            rg->head.state = UA_PUBSUBSTATE_PAUSED;
            UA_ReaderGroup_disconnect(rg);
            break;
        }

        /* Connection is not operational -> ReaderGroup paused */
        if(connection->head.state != UA_PUBSUBSTATE_OPERATIONAL) {
            UA_ReaderGroup_disconnect(rg);
            rg->head.state = UA_PUBSUBSTATE_PAUSED;
            break;
        }

        /* Connect RG-specific connections. For example for MQTT. */
        if(UA_ReaderGroup_canConnect(rg))
            ret = UA_ReaderGroup_connect(psm, rg, false);

        /* Preoperational until a message was received */
        rg->head.state = (rg->hasReceived) ?
            UA_PUBSUBSTATE_OPERATIONAL : UA_PUBSUBSTATE_PREOPERATIONAL;
        break;

        /* Unknown case */
    default:
        ret = UA_STATUSCODE_BADINTERNALERROR;
        break;
    }

    /* Failure */
    if(ret != UA_STATUSCODE_GOOD) {
        rg->head.state = UA_PUBSUBSTATE_ERROR;
        UA_ReaderGroup_disconnect(rg);
        rg->hasReceived = false;
    }

 finalize_state_machine:

    /* Only the top-level state update (if recursive calls are happening)
     * notifies the application and updates Reader and WriterGroups */
    rg->head.transientState = isTransient;
    if(rg->head.transientState)
        return ret;

    /* No state change has happened */
    if(rg->head.state == oldState)
        return ret;

    UA_LOG_INFO_PUBSUB(psm->logging, rg, "%s -> %s",
                       UA_PubSubState_name(oldState),
                       UA_PubSubState_name(rg->head.state));

    /* Inform application about state change */
    if(server->config.pubSubConfig.stateChangeCallback)
        server->config.pubSubConfig.
            stateChangeCallback(server, rg->head.identifier, rg->head.state, ret);

    /* Children evaluate their state machine after the state change of the parent.
     * Keep the current child state as the target state for the child. */
    UA_DataSetReader *dsr;
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
        if(psm->pubSubInitialSetupMode && dsr->config.enabled) {
            UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_PREOPERATIONAL, UA_STATUSCODE_GOOD);
        } else {
            UA_DataSetReader_setPubSubState(psm, dsr, dsr->head.state, UA_STATUSCODE_GOOD);
        }
    }

    /* Update the PubSubManager state. It will go from STOPPING to STOPPED when
     * the last socket has closed. */
    UA_PubSubManager_setState(psm, psm->sc.state);

    return ret;
}

UA_StatusCode
UA_ReaderGroup_setEncryptionKeys(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                                 UA_UInt32 securityTokenId,
                                 const UA_ByteString signingKey,
                                 const UA_ByteString encryptingKey,
                                 const UA_ByteString keyNonce) {
    if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "JSON encoding is enabled. The message security is "
                              "only defined for the UADP message mapping.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_PubSubSecurityPolicy *sp = rg->config.securityPolicy;
    if(!sp) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "No SecurityPolicy configured for the ReaderGroup");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(securityTokenId != rg->securityTokenId) {
        rg->securityTokenId = securityTokenId;
        rg->nonceSequenceNumber = 1;
    }

    /* Create a new context */
    if(!rg->securityPolicyContext) {
        return sp->newGroupContext(sp, &signingKey, &encryptingKey, &keyNonce,
                                   &rg->securityPolicyContext);
    }

    /* Update the context */
    return sp->setSecurityKeys(sp, rg->securityPolicyContext, &signingKey,
                               &encryptingKey, &keyNonce);
}

UA_Boolean
UA_ReaderGroup_process(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                       UA_NetworkMessage *nm) {
    /* Check if the ReaderGroup is enabled */
    if(rg->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
       rg->head.state != UA_PUBSUBSTATE_PREOPERATIONAL)
        return false;

    /* Set to operational if required */
    rg->hasReceived = true;
    UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);

    /* Safe iteration. The current Reader might be deleted in the ReaderGroup
     * _setPubSubState callback. */
    UA_Boolean processed = false;
    UA_DataSetReader *reader, *reader_tmp;
    LIST_FOREACH_SAFE(reader, &rg->readers, listEntry, reader_tmp) {
        /* Check if the reader is enabled */
        if(reader->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
           reader->head.state != UA_PUBSUBSTATE_PREOPERATIONAL)
            continue;

        UA_StatusCode res = UA_DataSetReader_checkIdentifier(psm, reader, nm);
        if(res != UA_STATUSCODE_GOOD)
            continue;

        /* Update the ReaderGroup state if this is the first received message */
        if(!rg->hasReceived) {
            rg->hasReceived = true;
            UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);
        }

        /* The message was processed by at least one reader */
        processed = true;

        UA_LOG_TRACE_PUBSUB(psm->logging, rg, "Processing a NetworkMessage");

        /* No payload header. The message ontains a single DataSetMessage that
         * is processed by every Reader. */
        if(!nm->payloadHeaderEnabled) {
            UA_DataSetReader_process(psm, reader, nm->payload.dataSetMessages);
            continue;
        }

        /* Process only the payloads where the WriterId from the header is expected */
        for(size_t i = 0; i < nm->messageCount; i++) {
            if(reader->config.dataSetWriterId == nm->dataSetWriterIds[i])
                UA_DataSetReader_process(psm, reader, &nm->payload.dataSetMessages[i]);
        }
    }

    return processed;
}

UA_StatusCode
UA_ReaderGroup_decodeNetworkMessage(UA_PubSubManager *psm,
                                    UA_ReaderGroup *rg,
                                    UA_ByteString buffer,
                                    UA_NetworkMessage *nm) {
    /* Set up the decoding context */
    PubSubDecodeCtx ctx;
    memset(&ctx, 0, sizeof(PubSubDecodeCtx));
    ctx.ctx.pos = buffer.data;
    ctx.ctx.end = buffer.data + buffer.length;
    ctx.ctx.opts.customTypes = psm->sc.server->config.customDataTypes;

    /* Decode the headers. This sets the number of DataSetMessages and retrieves
     * the DataSetWriterIds. Those get matched to the readers below. */
    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(&ctx, nm);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "PubSub receive. decoding headers failed");
        UA_NetworkMessage_clear(nm);
        return rv;
    }

    /* Find a matching reader. Otherwise skip for this ReaderGroup */
    UA_DataSetReader *dsr;
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
        rv = UA_DataSetReader_checkIdentifier(psm, dsr, nm);
        if(rv == UA_STATUSCODE_GOOD)
            break;
    }
    if(!dsr) {
        UA_NetworkMessage_clear(nm);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Prepare the metadata with information from the readers to decode the
     * DataSetMessages */
    size_t i = 0;
    UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, rg->readersCount);
    memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * rg->readersCount);
    ctx.eo.metaData = emd;
    ctx.eo.metaDataSize = rg->readersCount;
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
        emd[i].dataSetWriterId = dsr->config.dataSetWriterId;
        emd[i].fields = dsr->config.dataSetMetaData.fields;
        emd[i].fieldsSize = dsr->config.dataSetMetaData.fieldsSize;
        i++;
    }

    /* Handle missing payload header and "inject" metadata */
    if(!nm->payloadHeaderEnabled)
        UA_NetworkMessage_makeSyntheticPayloadHeader(&ctx.eo, nm);

    /* Decrypt */
    rv = verifyAndDecryptNetworkMessage(psm->logging, buffer, &ctx.ctx, nm, rg);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_NetworkMessage_clear(nm);
        return rv;
    }

    /* Decode the payload */
    rv = UA_NetworkMessage_decodePayload(&ctx, nm);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_NetworkMessage_clear(nm);
        return rv;
    }

    rv = UA_NetworkMessage_decodeFooters(&ctx, nm);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_NetworkMessage_clear(nm);
        return rv;
    }

    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_JSON_ENCODING
UA_StatusCode
UA_ReaderGroup_decodeNetworkMessageJSON(UA_PubSubManager *psm,
                                        UA_ReaderGroup *rg,
                                        UA_ByteString buffer,
                                        UA_NetworkMessage *nm) {
    /* Set up the decoding options */
    UA_DecodeJsonOptions jo;
    memset(&jo, 0, sizeof(jo));
    jo.customTypes = psm->sc.server->config.customDataTypes;

    /* Prepare the metadata with information from the readers to decode the
     * DataSetMessages */
    UA_NetworkMessage_EncodingOptions eo;
    size_t i = 0;
    UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, rg->readersCount);
    memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * rg->readersCount);
    eo.metaData = emd;
    eo.metaDataSize = rg->readersCount;

    UA_DataSetReader *dsr;
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
        emd[i].dataSetWriterId = dsr->config.dataSetWriterId;
        emd[i].fields = dsr->config.dataSetMetaData.fields;
        emd[i].fieldsSize = dsr->config.dataSetMetaData.fieldsSize;
        i++;
    }

    /* Decode */
    return UA_NetworkMessage_decodeJson(&buffer, nm, &eo, &jo);
}
#endif

/******************************/
/* Decrypt the NetworkMessage */
/******************************/

static UA_StatusCode
needsDecryption(const UA_Logger *logger,
                const UA_NetworkMessage *networkMessage,
                const UA_MessageSecurityMode securityMode,
                UA_Boolean *doDecrypt) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_Boolean requiresEncryption = securityMode > UA_MESSAGESECURITYMODE_SIGN;
    UA_Boolean isEncrypted = networkMessage->securityHeader.networkMessageEncrypted;

    if(isEncrypted && requiresEncryption) {
        *doDecrypt = true;
    } else if(!isEncrypted && !requiresEncryption) {
        *doDecrypt = false;
    } else {
        if(isEncrypted) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                         "PubSub receive. "
                         "Message is encrypted but ReaderGroup does not expect encryption");
            retval = UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;
        } else {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                         "PubSub receive. "
                         "Message is not encrypted but ReaderGroup requires encryption");
            retval = UA_STATUSCODE_BADSECURITYMODEREJECTED;
        }
    }
    return retval;
}

static UA_StatusCode
needsValidation(const UA_Logger *logger,
                const UA_NetworkMessage *networkMessage,
                const UA_MessageSecurityMode securityMode,
                UA_Boolean *doValidate) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_Boolean isSigned = networkMessage->securityHeader.networkMessageSigned;
    UA_Boolean requiresSignature = securityMode > UA_MESSAGESECURITYMODE_NONE;

    if(isSigned &&
       requiresSignature) {
        *doValidate = true;
    } else if(!isSigned && !requiresSignature) {
        *doValidate = false;
    } else {
        if(isSigned) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                         "PubSub receive. "
                         "Message is signed but ReaderGroup does not expect signatures");
            retval = UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;
        } else {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                         "PubSub receive. "
                         "Message is not signed but ReaderGroup requires signature");
            retval = UA_STATUSCODE_BADSECURITYMODEREJECTED;
        }
    }
    return retval;
}

UA_StatusCode
verifyAndDecryptNetworkMessage(const UA_Logger *logger, UA_ByteString buffer,
                               Ctx *ctx, UA_NetworkMessage *nm, UA_ReaderGroup *rg) {
    UA_MessageSecurityMode securityMode = rg->config.securityMode;
    UA_Boolean doValidate = false;
    UA_Boolean doDecrypt = false;

    UA_StatusCode rv = needsValidation(logger, nm, securityMode, &doValidate);
    UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
                         "PubSub receive. Validation security mode error");

    rv = needsDecryption(logger, nm, securityMode, &doDecrypt);
    UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
                         "PubSub receive. Decryption security mode error");

    if(!doValidate && !doDecrypt)
        return UA_STATUSCODE_GOOD;

    UA_PubSubSecurityPolicy *sp = rg->config.securityPolicy;
    UA_CHECK_MEM_ERROR(sp, return UA_STATUSCODE_BADINVALIDARGUMENT,
                       logger, UA_LOGCATEGORY_PUBSUB,
                       "PubSub receive. securityPolicy must be set when security mode"
                       "is enabled to sign and/or encrypt");

    void *cc = rg->securityPolicyContext;
    UA_CHECK_MEM_ERROR(cc, return UA_STATUSCODE_BADINVALIDARGUMENT,
                       logger, UA_LOGCATEGORY_PUBSUB,
                       "PubSub receive. securityPolicyContext must be initialized "
                       "when security mode is enabled to sign and/or encrypt");

    /* Validate the signature */
    if(doValidate) {
        size_t sigSize = sp->getSignatureSize(sp, cc);
        UA_ByteString toBeVerified = {buffer.length - sigSize, buffer.data};
        UA_ByteString signature = {sigSize, buffer.data + buffer.length - sigSize};

        rv = sp->verify(sp, cc, &toBeVerified, &signature);
        UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
                             "PubSub receive. Signature invalid");

        /* Remove the signature from the ctx->end. We do not want to decode that. */
        ctx->end -= sigSize;
    }

    /* Decrypt the content */
    if(doDecrypt) {
        const UA_ByteString nonce = {
            (size_t)nm->securityHeader.messageNonceSize,
            (UA_Byte*)(uintptr_t)nm->securityHeader.messageNonce
        };
        rv = sp->setMessageNonce(sp, cc, &nonce);
        UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
                             "PubSub receive. Faulty Nonce set");

        UA_ByteString toBeDecrypted = {(uintptr_t)(ctx->end - ctx->pos), ctx->pos};
        rv = sp->decrypt(sp, cc, &toBeDecrypted);
        UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
                             "PubSub receive. Faulty Decryption");
    }

    return UA_STATUSCODE_GOOD;
}

/***********************/
/* Connection Handling */
/***********************/

static UA_StatusCode
UA_ReaderGroup_connectMQTT(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                           UA_Boolean validate);

typedef struct  {
    UA_String profileURI;
    UA_String protocol;
    UA_Boolean json;
    UA_StatusCode (*connectReaderGroup)(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                                        UA_Boolean validate);
} ReaderGroupProfileMapping;

static ReaderGroupProfileMapping readerGroupProfiles[UA_PUBSUB_PROFILES_SIZE] = {
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"),
     UA_STRING_STATIC("udp"), false, NULL},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp"),
     UA_STRING_STATIC("mqtt"), false, UA_ReaderGroup_connectMQTT},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json"),
     UA_STRING_STATIC("mqtt"), true, UA_ReaderGroup_connectMQTT},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"),
     UA_STRING_STATIC("eth"), false, NULL}
};

static void
UA_ReaderGroup_detachConnection(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                                UA_ConnectionManager *cm, uintptr_t connectionId) {
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(rg->recvChannels[i] != connectionId)
            continue;
        UA_LOG_INFO_PUBSUB(psm->logging, rg, "Detach receive-connection %S %u",
                           cm->protocol, (unsigned)connectionId);
        rg->recvChannels[i] = 0;
        rg->recvChannelsSize--;
        return;
    }
}

static UA_StatusCode
UA_ReaderGroup_attachRecvConnection(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                                    UA_ConnectionManager *cm, uintptr_t connectionId) {
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(rg->recvChannels[i] == connectionId)
            return UA_STATUSCODE_GOOD;
    }
    if(rg->recvChannelsSize >= UA_PUBSUB_MAXCHANNELS)
        return UA_STATUSCODE_BADINTERNALERROR;
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(rg->recvChannels[i] != 0)
            continue;
        UA_LOG_INFO_PUBSUB(psm->logging, rg, "Attach receive-connection %S %u",
                           cm->protocol, (unsigned)connectionId);
        rg->recvChannels[i] = connectionId;
        rg->recvChannelsSize++;
        break;
    }
    return UA_STATUSCODE_GOOD;
}

static void
ReaderGroupChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                          void *application, void **connectionContext,
                          UA_ConnectionState state, const UA_KeyValueMap *params,
                          UA_ByteString msg) {
    if(!connectionContext)
        return;

    /* Get the context pointers */
    UA_ReaderGroup *rg = (UA_ReaderGroup*)*connectionContext;
    UA_PubSubManager *psm = (UA_PubSubManager*)application;
    UA_Server *server = psm->sc.server;

    lockServer(server);

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        /* Reset the connection identifiers */
        UA_ReaderGroup_detachConnection(psm, rg, cm, connectionId);

        /* PSC marked for deletion and the last EventLoop connection has closed */
        if(rg->deleteFlag && rg->recvChannelsSize == 0) {
            UA_ReaderGroup_remove(psm, rg);
            unlockServer(server);
            return;
        }

        /* Reconnect if still operational */
        UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);

        /* Switch the psm state from stopping to stopped once the last
         * connection has closed */
        UA_PubSubManager_setState(psm, psm->sc.state);

        unlockServer(server);
        return;
    }

    /* Store the connectionId (if a new connection) */
    UA_StatusCode res = UA_ReaderGroup_attachRecvConnection(psm, rg, cm, connectionId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "No more space for an additional EventLoop connection");
        UA_PubSubConnection *c = rg->linkedConnection;
        if(c && c->cm)
            c->cm->closeConnection(c->cm, connectionId);
        unlockServer(server);
        return;
    }

    /* The connection has opened - set the ReaderGroup to operational */
    UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);

    /* No message received */
    if(msg.length == 0) {
        unlockServer(server);
        return;
    }

    if(rg->head.state != UA_PUBSUBSTATE_OPERATIONAL) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "Received a messaage for a non-operational ReaderGroup");
        unlockServer(server);
        return;
    }

    /* Decode message */
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));
    if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP) {
        res = UA_ReaderGroup_decodeNetworkMessage(psm, rg, msg, &nm);
    } else { /* if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) */
#ifdef UA_ENABLE_JSON_ENCODING
        res = UA_ReaderGroup_decodeNetworkMessageJSON(psm, rg, msg, &nm);
#else
        res = UA_STATUSCODE_BADNOTSUPPORTED;
#endif
    }
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
                              "Verify, decrypt and decode network message failed");
        unlockServer(server);
        return;
    }

    /* Process the decoded message */
    UA_ReaderGroup_process(psm, rg, &nm);
    UA_NetworkMessage_clear(&nm);
    unlockServer(server);
}

static UA_StatusCode
UA_ReaderGroup_connectMQTT(UA_PubSubManager *psm, UA_ReaderGroup *rg,
                           UA_Boolean validate) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PubSubConnection *c = rg->linkedConnection;
    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Get the TransportSettings */
    UA_ExtensionObject *ts = &rg->config.transportSettings;
    if((ts->encoding != UA_EXTENSIONOBJECT_DECODED &&
        ts->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       ts->content.decoded.type !=
       &UA_TYPES[UA_TYPES_BROKERDATASETREADERTRANSPORTDATATYPE]) {
        UA_LOG_ERROR_PUBSUB(psm->logging, rg,
                            "Wrong TransportSettings type for MQTT");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_BrokerDataSetReaderTransportDataType *transportSettings =
        (UA_BrokerDataSetReaderTransportDataType*)ts->content.decoded.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port = 1883; /* Default */
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "Could not parse the MQTT network URL");
        return res;
    }

    /* Set up the connection parameters.
     * TODO: Complete the MQTT parameters. */
    UA_Boolean listen = true;
    UA_KeyValuePair kvp[5];
    UA_KeyValueMap kvm = {5, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "subscribe");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[2].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "topic");
    UA_Variant_setScalar(&kvp[3].value, &transportSettings->queueName,
                         &UA_TYPES[UA_TYPES_STRING]);
    kvp[4].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[4].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* Connect */
    res = c->cm->openConnection(c->cm, &kvm, psm, rg, ReaderGroupChannelCallback);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, rg, "Could not open the MQTT connection");
    }
    return res;
}

void
UA_ReaderGroup_disconnect(UA_ReaderGroup *rg) {
    UA_PubSubConnection *c = rg->linkedConnection;
    if(!c)
        return;
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(rg->recvChannels[i] != 0)
            c->cm->closeConnection(c->cm, rg->recvChannels[i]);
    }
}

UA_Boolean
UA_ReaderGroup_canConnect(UA_ReaderGroup *rg) {
    return rg->recvChannelsSize == 0;
}

UA_StatusCode
UA_ReaderGroup_connect(UA_PubSubManager *psm, UA_ReaderGroup *rg, UA_Boolean validate) {
    UA_Server *server = psm->sc.server;
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Is this a ReaderGroup with custom TransportSettings beyond the
     * PubSubConnection? */
    if(rg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return UA_STATUSCODE_GOOD;

    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    if(!el) {
        UA_LOG_ERROR_PUBSUB(server->config.logging, rg, "No EventLoop configured");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_PubSubConnection *c = rg->linkedConnection;
    if(!c)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Look up the connection manager for the connection */
    ReaderGroupProfileMapping *profile = NULL;
    for(size_t i = 0; i < UA_PUBSUB_PROFILES_SIZE; i++) {
        if(!UA_String_equal(&c->config.transportProfileUri,
                            &readerGroupProfiles[i].profileURI))
            continue;
        profile = &readerGroupProfiles[i];
        break;
    }

    UA_ConnectionManager *cm = (profile) ? getCM(el, profile->protocol) : NULL;
    if(!cm || (c->cm && cm != c->cm)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, c,
                            "The requested profile \"%S\"is not supported",
                            c->config.transportProfileUri);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    c->cm = cm;
    c->json = profile->json;

    /* If no ReaderGroup-specific connections, the ReaderGroup is set to
     * operational when we return. */
    return (profile->connectReaderGroup) ?
        profile->connectReaderGroup(psm, rg, validate) : UA_STATUSCODE_GOOD;
}

/**************/
/* Server API */
/**************/

UA_StatusCode
UA_Server_addReaderGroup(UA_Server *server, const UA_NodeId connectionIdentifier,
                         const UA_ReaderGroupConfig *readerGroupConfig,
                         UA_NodeId *readerGroupIdentifier) {
    if(!server || !readerGroupConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode res =
        UA_ReaderGroup_create(psm, connectionIdentifier,
                              readerGroupConfig, readerGroupIdentifier);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_removeReaderGroup(UA_Server *server, const UA_NodeId groupIdentifier) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_PubSubManager *psm = getPSM(server);
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, groupIdentifier);
    if(rg)
        UA_ReaderGroup_remove(psm, rg);
    else
        res = UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_getReaderGroupConfig(UA_Server *server, const UA_NodeId rgId,
                               UA_ReaderGroupConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), rgId);
    UA_StatusCode ret = (rg) ?
        UA_ReaderGroupConfig_copy(&rg->config, config) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return ret;
}

UA_StatusCode
UA_Server_getReaderGroupState(UA_Server *server, const UA_NodeId rgId,
                              UA_PubSubState *state) {
    if(!server || !state)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_StatusCode ret = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), rgId);
    if(rg) {
        *state = rg->head.state;
        ret = UA_STATUSCODE_GOOD;
    }
    unlockServer(server);
    return ret;
}

#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
UA_Server_setReaderGroupActivateKey(UA_Server *server,
                                    const UA_NodeId readerGroupId) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupId);
    if(!rg || !rg->keyStorage || !rg->keyStorage->currentItem) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode ret =
        UA_PubSubKeyStorage_activateKeyToChannelContext(psm, rg->head.identifier,
                                                        rg->config.securityGroupId);
    unlockServer(server);
    return ret;
}
#endif

UA_StatusCode
UA_Server_enableReaderGroup(UA_Server *server, const UA_NodeId readerGroupId){
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupId);
    UA_StatusCode ret = (rg) ?
        UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_OPERATIONAL) :
        UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return ret;
}

UA_StatusCode
UA_Server_disableReaderGroup(UA_Server *server, const UA_NodeId readerGroupId){
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupId);
    UA_StatusCode ret = (rg) ?
        UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED) :
        UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return ret;
}

UA_StatusCode
UA_Server_setReaderGroupEncryptionKeys(UA_Server *server,
                                       const UA_NodeId readerGroup,
                                       UA_UInt32 securityTokenId,
                                       const UA_ByteString signingKey,
                                       const UA_ByteString encryptingKey,
                                       const UA_ByteString keyNonce) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), readerGroup);
    UA_StatusCode res = (rg) ?
        UA_ReaderGroup_setEncryptionKeys(psm, rg, securityTokenId, signingKey,
                                         encryptingKey, keyNonce) : UA_STATUSCODE_BADNOTFOUND;
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_updateReaderGroupConfig(UA_Server *server, const UA_NodeId rgId,
                                  const UA_ReaderGroupConfig *config) {
    if(!server || !config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    lockServer(server);

    UA_PubSubManager *psm = getPSM(server);
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), rgId);
    if(!rg) {
        unlockServer(server);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    if(UA_PubSubState_isEnabled(rg->head.state)) {
        UA_LOG_ERROR_PUBSUB(psm->logging, rg,
                            "The ReaderGroup must be disabled to update the config");
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Store the old config */
    UA_ReaderGroupConfig oldConfig = rg->config;

    /* Deep copy of the config */
    UA_StatusCode retval = UA_ReaderGroupConfig_copy(config, &rg->config);
    if(retval != UA_STATUSCODE_GOOD) {
        unlockServer(server);
        return retval;
    }

    /* Validate the connection settings */
    retval = UA_ReaderGroup_connect(psm, rg, true);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_PUBSUB(psm->logging, rg,
                            "Could not validate the connection parameters");
        goto errout;
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    if(!UA_String_equal(&rg->config.securityGroupId, &oldConfig.securityGroupId) ||
       rg->config.securityMode != oldConfig.securityMode) {
        /* Detach keystorage and reattach if needed */
        if(rg->keyStorage) {
            UA_PubSubKeyStorage_detachKeyStorage(psm, rg->keyStorage);
            rg->keyStorage = NULL;
        }
        if(rg->config.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
           rg->config.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
            retval = readerGroupAttachSKSKeystorage(psm, rg);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR_PUBSUB(psm->logging, rg,
                                    "Attaching the SKS KeyStorage failed");
                goto errout;
            }
        }
    }
#endif

    /* Clean up and return */
    UA_ReaderGroupConfig_clear(&oldConfig);
    unlockServer(server);
    return UA_STATUSCODE_GOOD;

 errout:
    UA_ReaderGroupConfig_clear(&rg->config);
    rg->config = oldConfig;
    unlockServer(server);
    return retval;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_manager.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2025 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2018 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

#ifdef UA_ENABLE_PUBSUB_SKS
#endif

#define UA_DATETIMESTAMP_2000 125911584000000000
#define UA_RESERVEID_FIRST_ID 0x8000

static const char *pubSubStateNames[6] = {
    "Disabled", "Paused", "Operational", "Error", "PreOperational", "Invalid"
};

static void
UA_PubSubManager_stop(UA_ServerComponent *sc);

static UA_StatusCode
UA_PubSubManager_start(UA_ServerComponent *sc, UA_Server *server);

const char *
UA_PubSubState_name(UA_PubSubState state) {
    if(state < UA_PUBSUBSTATE_DISABLED || state > UA_PUBSUBSTATE_PREOPERATIONAL)
        return pubSubStateNames[5];
    return pubSubStateNames[state];
}

void
UA_PubSubComponentHead_clear(UA_PubSubComponentHead *psch) {
    UA_NodeId_clear(&psch->identifier);
    UA_String_clear(&psch->logIdString);
    memset(psch, 0, sizeof(UA_PubSubComponentHead));
}

UA_StatusCode
UA_PublisherId_copy(const UA_PublisherId *src,
                    UA_PublisherId *dst) {
    memcpy(dst, src, sizeof(UA_PublisherId));
    if(src->idType == UA_PUBLISHERIDTYPE_STRING)
        return UA_String_copy(&src->id.string, &dst->id.string);
    return UA_STATUSCODE_GOOD;
}

void
UA_PublisherId_clear(UA_PublisherId *p) {
    if(p->idType == UA_PUBLISHERIDTYPE_STRING)
        UA_String_clear(&p->id.string);
    memset(p, 0, sizeof(UA_PublisherId));
}

UA_StatusCode
UA_PublisherId_fromVariant(UA_PublisherId *p, const UA_Variant *src) {
    if(!UA_Variant_isScalar(src))
        return UA_STATUSCODE_BADINTERNALERROR;

    memset(p, 0, sizeof(UA_PublisherId));

    const void *data = (const void*)src->data;
    if(src->type == &UA_TYPES[UA_TYPES_BYTE]) {
        p->idType = UA_PUBLISHERIDTYPE_BYTE;
        p->id.byte = *(const UA_Byte*)data;
    } else if(src->type == &UA_TYPES[UA_TYPES_UINT16]) {
        p->idType  = UA_PUBLISHERIDTYPE_UINT16;
        p->id.uint16 = *(const UA_UInt16*)data;
    } else if(src->type == &UA_TYPES[UA_TYPES_UINT32]) {
        p->idType  = UA_PUBLISHERIDTYPE_UINT32;
        p->id.uint32 = *(const UA_UInt32*)data;
    } else if(src->type == &UA_TYPES[UA_TYPES_UINT64]) {
        p->idType  = UA_PUBLISHERIDTYPE_UINT64;
        p->id.uint64 = *(const UA_UInt64*)data;
    } else if(src->type == &UA_TYPES[UA_TYPES_STRING]) {
        p->idType  = UA_PUBLISHERIDTYPE_STRING;
        return UA_String_copy((const UA_String *)data, &p->id.string);
    } else {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

void
UA_PublisherId_toVariant(const UA_PublisherId *p, UA_Variant *dst) {
    UA_PublisherId *p2 = (UA_PublisherId*)(uintptr_t)p;
    switch(p->idType) {
    case UA_PUBLISHERIDTYPE_BYTE:
        UA_Variant_setScalar(dst, &p2->id.byte, &UA_TYPES[UA_TYPES_BYTE]); break;
    case UA_PUBLISHERIDTYPE_UINT16:
        UA_Variant_setScalar(dst, &p2->id.uint16, &UA_TYPES[UA_TYPES_UINT16]); break;
    case UA_PUBLISHERIDTYPE_UINT32:
        UA_Variant_setScalar(dst, &p2->id.uint32, &UA_TYPES[UA_TYPES_UINT32]); break;
    case UA_PUBLISHERIDTYPE_UINT64:
        UA_Variant_setScalar(dst, &p2->id.uint64, &UA_TYPES[UA_TYPES_UINT64]); break;
    case UA_PUBLISHERIDTYPE_STRING:
        UA_Variant_setScalar(dst, &p2->id.string, &UA_TYPES[UA_TYPES_STRING]); break;
    default: break; /* This is not possible if the PublisherId is well-defined */
    }
}

UA_ConnectionManager *
getCM(UA_EventLoop *el, UA_String protocol) {
    for(UA_EventSource *es = el->eventSources; es != NULL; es = es->next) {
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(UA_String_equal(&protocol, &cm->protocol))
            return cm;
    }
    return NULL;
}

static enum ZIP_CMP
cmpReserveId(const void *a, const void *b) {
    const UA_ReserveId *aa = (const UA_ReserveId*)a;
    const UA_ReserveId *bb = (const UA_ReserveId*)b;
    if(aa->id != bb->id)
        return (aa->id < bb->id) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    if(aa->reserveIdType != bb->reserveIdType)
        return (aa->reserveIdType < bb->reserveIdType) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    return (enum ZIP_CMP)UA_order(&aa->transportProfileUri,
                                  &bb->transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
}

ZIP_FUNCTIONS(UA_ReserveIdTree, UA_ReserveId, treeEntry, UA_ReserveId, id, cmpReserveId)

static UA_ReserveId *
UA_ReserveId_new(UA_UInt16 id, UA_String transportProfileUri,
                 UA_ReserveIdType reserveIdType, UA_NodeId sessionId) {
    UA_ReserveId *reserveId = (UA_ReserveId *)UA_calloc(1, sizeof(UA_ReserveId));
    if(!reserveId)
        return NULL;
    reserveId->id = id;
    reserveId->reserveIdType = reserveIdType;
    UA_String_copy(&transportProfileUri, &reserveId->transportProfileUri);
    reserveId->sessionId = sessionId;
    return reserveId;
}

static UA_Boolean
UA_ReserveId_isFree(UA_PubSubManager *psm, UA_UInt16 id, UA_String transportProfileUri,
                    UA_ReserveIdType reserveIdType) {
    /* Is the id already in use? */
    UA_ReserveId compare;
    compare.id = id;
    compare.reserveIdType = reserveIdType;
    compare.transportProfileUri = transportProfileUri;
    if(ZIP_FIND(UA_ReserveIdTree, &psm->reserveIds, &compare))
        return false;

    UA_PubSubConnection *tmpConnection;
    TAILQ_FOREACH(tmpConnection, &psm->connections, listEntry) {
        UA_WriterGroup *writerGroup;
        LIST_FOREACH(writerGroup, &tmpConnection->writerGroups, listEntry) {
            if(reserveIdType == UA_WRITER_GROUP) {
                if(UA_String_equal(&tmpConnection->config.transportProfileUri,
                                   &transportProfileUri) &&
                   writerGroup->config.writerGroupId == id)
                    return false;
            /* reserveIdType == UA_DATA_SET_WRITER */
            } else {
                UA_DataSetWriter *currentWriter;
                LIST_FOREACH(currentWriter, &writerGroup->writers, listEntry) {
                    if(UA_String_equal(&tmpConnection->config.transportProfileUri,
                                       &transportProfileUri) &&
                       currentWriter->config.dataSetWriterId == id)
                        return false;
                }
            }
        }
    }
    return true;
}

static UA_UInt16
UA_ReserveId_createId(UA_PubSubManager *psm,  UA_NodeId sessionId,
                      UA_String transportProfileUri, UA_ReserveIdType reserveIdType) {
    /* Total number of possible Ids */
    UA_UInt16 numberOfIds = 0x8000;
    /* Contains next possible free Id */
    static UA_UInt16 next_id_writerGroup = UA_RESERVEID_FIRST_ID;
    static UA_UInt16 next_id_writer = UA_RESERVEID_FIRST_ID;
    UA_UInt16 next_id;
    UA_Boolean is_free = false;

    if(reserveIdType == UA_WRITER_GROUP)
        next_id = next_id_writerGroup;
    else
        next_id = next_id_writer;

    for(;numberOfIds > 0;numberOfIds--) {
        if(next_id < UA_RESERVEID_FIRST_ID)
            next_id = UA_RESERVEID_FIRST_ID;
        is_free = UA_ReserveId_isFree(psm, next_id, transportProfileUri, reserveIdType);
        if(is_free)
            break;
        next_id++;
    }
    if(!is_free) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PubSub ReserveId creation failed. No free ID could be found.");
        return 0;
    }

    if(reserveIdType == UA_WRITER_GROUP)
        next_id_writerGroup = (UA_UInt16)(next_id + 1);
    else
        next_id_writer = (UA_UInt16)(next_id + 1);

    UA_ReserveId *reserveId =
        UA_ReserveId_new(next_id, transportProfileUri, reserveIdType, sessionId);
    if(!reserveId)
        return 0;

    ZIP_INSERT(UA_ReserveIdTree, &psm->reserveIds, reserveId);
    psm->reserveIdsSize++;
    return next_id;
}

static void *
removeReserveId(void *context, UA_ReserveId *elem) {
    UA_String_clear(&elem->transportProfileUri);
    UA_free(elem);
    return NULL;
}

struct RemoveInactiveReserveIdContext {
    UA_PubSubManager *psm;
    UA_ReserveIdTree newTree;
};

/* Remove ReserveIds that are not attached to any session */
static void *
removeInactiveReserveId(void *context, UA_ReserveId *elem) {
    struct RemoveInactiveReserveIdContext *ctx =
        (struct RemoveInactiveReserveIdContext*)context;

    if(UA_NodeId_equal(&ctx->psm->sc.server->adminSession.sessionId, &elem->sessionId))
        goto still_active;

    session_list_entry *session;
    LIST_FOREACH(session, &ctx->psm->sc.server->sessions, pointers) {
        if(UA_NodeId_equal(&session->session.sessionId, &elem->sessionId))
            goto still_active;
    }

    ctx->psm->reserveIdsSize--;
    UA_String_clear(&elem->transportProfileUri);
    UA_free(elem);
    return NULL;

 still_active:
    ZIP_INSERT(UA_ReserveIdTree, &ctx->newTree, elem);
    return NULL;
}

void
UA_PubSubManager_freeIds(UA_PubSubManager *psm) {
    struct RemoveInactiveReserveIdContext removeCtx;
    removeCtx.psm = psm;
    removeCtx.newTree.root = NULL;
    ZIP_ITER(UA_ReserveIdTree, &psm->reserveIds,
             removeInactiveReserveId, &removeCtx);
    psm->reserveIds = removeCtx.newTree;
}

UA_StatusCode
UA_PubSubManager_reserveIds(UA_PubSubManager *psm, UA_NodeId sessionId, UA_UInt16 numRegWriterGroupIds,
                            UA_UInt16 numRegDataSetWriterIds, UA_String transportProfileUri,
                            UA_UInt16 **writerGroupIds, UA_UInt16 **dataSetWriterIds) {
    UA_PubSubManager_freeIds(psm);

    /* Check the validation of the transportProfileUri */
    UA_String profile_1 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp");
    UA_String profile_2 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json");
    UA_String profile_3 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
    if(!UA_String_equal(&transportProfileUri, &profile_1) &&
       !UA_String_equal(&transportProfileUri, &profile_2) &&
       !UA_String_equal(&transportProfileUri, &profile_3)) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "PubSub ReserveId creation failed. No valid transport profile uri.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    *writerGroupIds = (UA_UInt16*)UA_Array_new(numRegWriterGroupIds, &UA_TYPES[UA_TYPES_UINT16]);
    *dataSetWriterIds = (UA_UInt16*)UA_Array_new(numRegDataSetWriterIds, &UA_TYPES[UA_TYPES_UINT16]);

    for(int i = 0; i < numRegWriterGroupIds; i++) {
        (*writerGroupIds)[i] =
            UA_ReserveId_createId(psm, sessionId, transportProfileUri, UA_WRITER_GROUP);
    }
    for(int i = 0; i < numRegDataSetWriterIds; i++) {
        (*dataSetWriterIds)[i] =
            UA_ReserveId_createId(psm, sessionId, transportProfileUri, UA_DATA_SET_WRITER);
    }
    return UA_STATUSCODE_GOOD;
}

/* Calculate the time difference between current time and UTC (00:00) on January
 * 1, 2000. */
UA_UInt32
UA_PubSubConfigurationVersionTimeDifference(UA_DateTime now) {
    UA_UInt32 timeDiffSince2000 = (UA_UInt32)(now - UA_DATETIMESTAMP_2000);
    return timeDiffSince2000;
}

/* Generate a new unique NodeId. This NodeId will be used for the information
 * model representation of PubSub entities. */
#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
void
UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId) {
    *nodeId = UA_NODEID_NUMERIC(1, ++psm->uniqueIdCount);
}
#endif

UA_Guid
UA_PubSubManager_generateUniqueGuid(UA_PubSubManager *psm) {
    while(true) {
        UA_NodeId testId = UA_NODEID_GUID(1, UA_Guid_random());
        const UA_Node *testNode = UA_NODESTORE_GET(psm->sc.server, &testId);
        if(!testNode)
            return testId.identifier.guid;
        UA_NODESTORE_RELEASE(psm->sc.server, testNode);
    }
}

static UA_UInt64
generateRandomUInt64(void) {
    UA_UInt64 id = 0;
    UA_Guid ident = UA_Guid_random();

    id = id + ident.data1;
    id = (id << 32) + ident.data2;
    id = (id << 16) + ident.data3;
    return id;
}

UA_StatusCode
UA_Server_enableAllPubSubComponents(UA_Server *server) {
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    if(!psm) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode res = UA_PubSubManager_start(&psm->sc, server);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            UA_DataSetWriter *dsw;
            LIST_FOREACH(dsw, &wg->writers, listEntry) {
                res |= UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_OPERATIONAL);
            }
            res |= UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_OPERATIONAL);
        }

        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &c->readerGroups, listEntry) {
            UA_DataSetReader *dsr;
            LIST_FOREACH(dsr, &rg->readers, listEntry) {
                UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_OPERATIONAL,
                                                UA_STATUSCODE_GOOD);
            }
            res |= UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_OPERATIONAL);
        }

        res |= UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_OPERATIONAL);
    }

    unlockServer(server);
    return res;
}

static void
disableAllPubSubComponents(UA_PubSubManager *psm) {
    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &c->readerGroups, listEntry) {
            UA_DataSetReader *dsr;
            LIST_FOREACH(dsr, &rg->readers, listEntry) {
                UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_DISABLED,
                                                UA_STATUSCODE_BADSHUTDOWN);
            }
            UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED);
        }

        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            UA_DataSetWriter *dsw;
            LIST_FOREACH(dsw, &wg->writers, listEntry) {
                UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_DISABLED);
            }
            UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_DISABLED);
        }

        UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_DISABLED);
    }
}

void
UA_Server_disableAllPubSubComponents(UA_Server *server) {
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    if(psm)
        UA_PubSubManager_stop(&psm->sc); /* Calls disableAll internally */
    unlockServer(server);
}

static UA_StatusCode
getPubSubComponentType(UA_PubSubManager *psm, UA_NodeId componentId,
                       UA_PubSubComponentType *outType) {
    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        if(UA_NodeId_equal(&componentId, &c->head.identifier)) {
            *outType = c->head.componentType;
            return UA_STATUSCODE_GOOD;
        }

        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            if(UA_NodeId_equal(&componentId, &wg->head.identifier)) {
                *outType = wg->head.componentType;
                return UA_STATUSCODE_GOOD;
            }

            UA_DataSetWriter *dsw;
            LIST_FOREACH(dsw, &wg->writers, listEntry) {
                if(UA_NodeId_equal(&componentId, &dsw->head.identifier)) {
                    *outType = dsw->head.componentType;
                    return UA_STATUSCODE_GOOD;
                }
            }
        }

        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &c->readerGroups, listEntry) {
            if(UA_NodeId_equal(&componentId, &rg->head.identifier)) {
                *outType = rg->head.componentType;
                return UA_STATUSCODE_GOOD;
            }

            UA_DataSetReader *dsr;
            LIST_FOREACH(dsr, &rg->readers, listEntry) {
                if(UA_NodeId_equal(&componentId, &dsr->head.identifier)) {
                    *outType = dsr->head.componentType;
                    return UA_STATUSCODE_GOOD;
                }
            }
        }
    }

    return UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
UA_Server_getPubSubComponentType(UA_Server *server, UA_NodeId componentId,
                                 UA_PubSubComponentType *outType) {
    if(!outType)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode res = (psm) ?
        getPubSubComponentType(psm, componentId, outType) : UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

static UA_StatusCode
getPubSubComponentParent(UA_PubSubManager *psm, UA_NodeId componentId,
                         UA_NodeId *outParent) {
    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        if(UA_NodeId_equal(&componentId, &c->head.identifier))
            return UA_STATUSCODE_BADNOTSUPPORTED;

        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            if(UA_NodeId_equal(&componentId, &wg->head.identifier))
                return UA_NodeId_copy(&c->head.identifier, outParent);

            UA_DataSetWriter *dsw;
            LIST_FOREACH(dsw, &wg->writers, listEntry) {
                if(UA_NodeId_equal(&componentId, &dsw->head.identifier))
                    return UA_NodeId_copy(&wg->head.identifier, outParent);
            }
        }

        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &c->readerGroups, listEntry) {
            if(UA_NodeId_equal(&componentId, &rg->head.identifier))
                return UA_NodeId_copy(&c->head.identifier, outParent);

            UA_DataSetReader *dsr;
            LIST_FOREACH(dsr, &rg->readers, listEntry) {
                if(UA_NodeId_equal(&componentId, &dsr->head.identifier))
                    return UA_NodeId_copy(&rg->head.identifier, outParent);
            }
        }
    }

    return UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
UA_Server_getPubSubComponentParent(UA_Server *server, UA_NodeId componentId,
                                   UA_NodeId *outParent) {
    if(!outParent)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode res = (psm) ?
        getPubSubComponentParent(psm, componentId, outParent) : UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

static UA_StatusCode
getPubSubComponentChildren(UA_PubSubManager *psm, UA_NodeId componentId,
                           size_t *outChildrenSize, UA_NodeId **outChildren) {
    UA_WriterGroup *wg;
    UA_ReaderGroup *rg;
    UA_DataSetWriter *dsw;
    UA_DataSetReader *dsr;
    UA_PubSubConnection *c;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        if(UA_NodeId_equal(&componentId, &c->head.identifier)) {
            /* Count the children */
            size_t children = 0;
            LIST_FOREACH(wg, &c->writerGroups, listEntry)
                children++;
            LIST_FOREACH(rg, &c->readerGroups, listEntry)
                children++;

            /* Empty array? */
            if(children == 0) {
                *outChildren = NULL;
                *outChildrenSize = 0;
                return UA_STATUSCODE_GOOD;
            }

            /* Allocate the array */
            *outChildren = (UA_NodeId*)UA_calloc(children, sizeof(UA_NodeId));
            if(!*outChildren)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            *outChildrenSize = children;

            /* Copy the NodeIds */
            size_t pos = 0;
            LIST_FOREACH(wg, &c->writerGroups, listEntry) {
                res |= UA_NodeId_copy(&wg->head.identifier, (*outChildren) + pos);
                pos++;
            }
            LIST_FOREACH(rg, &c->readerGroups, listEntry) {
                res |= UA_NodeId_copy(&rg->head.identifier, (*outChildren) + pos);
                pos++;
            }
            goto out;
        }

        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            if(UA_NodeId_equal(&componentId, &wg->head.identifier)) {
                /* Count the children */
                size_t children = 0;
                LIST_FOREACH(dsw, &wg->writers, listEntry)
                    children++;

                /* Empty array? */
                if(children == 0) {
                    *outChildren = NULL;
                    *outChildrenSize = 0;
                    return UA_STATUSCODE_GOOD;
                }

                /* Allocate the array */
                *outChildren = (UA_NodeId*)UA_calloc(children, sizeof(UA_NodeId));
                if(!*outChildren)
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                *outChildrenSize = children;

                /* Copy the NodeIds */
                size_t pos = 0;
                LIST_FOREACH(dsw, &wg->writers, listEntry) {
                    res |= UA_NodeId_copy(&dsw->head.identifier, (*outChildren) + pos);
                    pos++;
                }
                goto out;
            }

            /* DataSetWriter have no children (with a state machine) */
            LIST_FOREACH(dsw, &wg->writers, listEntry) {
                if(UA_NodeId_equal(&componentId, &dsw->head.identifier))
                    return UA_STATUSCODE_BADNOTSUPPORTED;
            }
        }

        LIST_FOREACH(rg, &c->readerGroups, listEntry) {
            if(UA_NodeId_equal(&componentId, &rg->head.identifier)) {
                /* Count the children */
                size_t children = 0;
                LIST_FOREACH(dsr, &rg->readers, listEntry)
                    children++;

                /* Empty array? */
                if(children == 0) {
                    *outChildren = NULL;
                    *outChildrenSize = 0;
                    return UA_STATUSCODE_GOOD;
                }

                /* Allocate the array */
                *outChildren = (UA_NodeId*)UA_calloc(children, sizeof(UA_NodeId));
                if(!*outChildren)
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                *outChildrenSize = children;

                /* Copy the NodeIds */
                size_t pos = 0;
                LIST_FOREACH(dsr, &rg->readers, listEntry) {
                    res |= UA_NodeId_copy(&dsr->head.identifier, (*outChildren) + pos);
                    pos++;
                }
                goto out;
            }

            /* DataSetReader have no children (with a state machine) */
            LIST_FOREACH(dsr, &rg->readers, listEntry) {
                if(UA_NodeId_equal(&componentId, &dsr->head.identifier))
                    return UA_STATUSCODE_BADNOTSUPPORTED;
            }
        }
    }

    return UA_STATUSCODE_BADNOTFOUND;

 out:
    if(res != UA_STATUSCODE_GOOD)
        UA_Array_delete(*outChildren, *outChildrenSize, &UA_TYPES[UA_TYPES_NODEID]);
    return res;
}

UA_StatusCode
UA_Server_getPubSubComponentChildren(UA_Server *server, UA_NodeId componentId,
                                     size_t *outChildrenSize, UA_NodeId **outChildren) {
    if(!outChildrenSize || !outChildren)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode res = (psm) ?
        getPubSubComponentChildren(psm, componentId,
                                   outChildrenSize, outChildren) : UA_STATUSCODE_BADINTERNALERROR;
    unlockServer(server);
    return res;
}

void
UA_PubSubManager_setState(UA_PubSubManager *psm, UA_LifecycleState state) {
    if(state == UA_LIFECYCLESTATE_STOPPED)
        state = UA_LIFECYCLESTATE_STOPPING;

    /* Check if all connections are closed if we are started */
    if(state == UA_LIFECYCLESTATE_STOPPING) {
        UA_PubSubConnection *c;
        TAILQ_FOREACH(c, &psm->connections, listEntry) {
            if(c->sendChannel != 0 || c->recvChannelsSize > 0)
                goto set_state;

            UA_WriterGroup *wg;
            LIST_FOREACH(wg, &c->writerGroups, listEntry) {
                if(wg->sendChannel > 0)
                    goto set_state;
            }

            UA_ReaderGroup *rg;
            LIST_FOREACH(rg, &c->readerGroups, listEntry) {
                if(rg->recvChannelsSize > 0)
                    goto set_state;
            }
        }

        /* No open connections -> stopped */
        state = UA_LIFECYCLESTATE_STOPPED;
    }

 set_state:
    if(state == psm->sc.state)
        return;
    psm->sc.state = state;
    if(psm->sc.notifyState)
        psm->sc.notifyState(&psm->sc, state);

    /* When we just started, trigger all connections to go from PAUSED to
     * OPERATIONAL */
    if(state == UA_LIFECYCLESTATE_STARTED) {
        UA_PubSubConnection *c;
        TAILQ_FOREACH(c, &psm->connections, listEntry) {
            if (psm->pubSubInitialSetupMode) {
                UA_PubSubConnection_setPubSubState(psm, c, UA_PUBSUBSTATE_OPERATIONAL);
            } else {
                UA_PubSubConnection_setPubSubState(psm, c, c->head.state);
            }
        }
    }
}

static UA_StatusCode
UA_PubSubManager_start(UA_ServerComponent *sc, UA_Server *server) {
    UA_PubSubManager *psm = (UA_PubSubManager*)sc;
    if(psm->sc.state == UA_LIFECYCLESTATE_STOPPING) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "The PubSubManager is still stopping");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Re-cache for the case that the configuration has been updated */
    psm->logging = server->config.logging;

    UA_PubSubManager_setState(psm, UA_LIFECYCLESTATE_STARTED);

    return UA_STATUSCODE_GOOD;
}

static void
UA_PubSubManager_stop(UA_ServerComponent *sc) {
    UA_PubSubManager *psm = (UA_PubSubManager*)sc;
    disableAllPubSubComponents(psm);
    UA_PubSubManager_setState(psm, UA_LIFECYCLESTATE_STOPPED);
}

UA_StatusCode
UA_PubSubManager_clear(UA_PubSubManager *psm) {
    if(psm->sc.state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "Cannot delete the PubSubManager because "
                     "it is not stopped");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Remove Connections - this also remove WriterGroups and ReaderGroups */
    UA_PubSubConnection *c, *tmpC;
    TAILQ_FOREACH_SAFE(c, &psm->connections, listEntry, tmpC) {
        UA_PubSubConnection_delete(psm, c);
    }

    /* Remove the DataSets */
    UA_PublishedDataSet *tmpPDS1, *tmpPDS2;
    TAILQ_FOREACH_SAFE(tmpPDS1, &psm->publishedDataSets, listEntry, tmpPDS2) {
        UA_PublishedDataSet_remove(psm, tmpPDS1);
    }

    /* Remove the ReserveIds*/
    ZIP_ITER(UA_ReserveIdTree, &psm->reserveIds, removeReserveId, NULL);
    psm->reserveIdsSize = 0;

    /* Delete subscribed datasets */
    UA_SubscribedDataSet *tmpSDS1, *tmpSDS2;
    TAILQ_FOREACH_SAFE(tmpSDS1, &psm->subscribedDataSets, listEntry, tmpSDS2) {
        UA_SubscribedDataSet_remove(psm, tmpSDS1);
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    /* Remove the SecurityGroups */
    UA_SecurityGroup *tmpSG1, *tmpSG2;
    TAILQ_FOREACH_SAFE(tmpSG1, &psm->securityGroups, listEntry, tmpSG2) {
        UA_SecurityGroup_remove(psm, tmpSG1);
    }

    /* Remove the keyStorages */
    UA_PubSubKeyStorage *ks, *ksTmp;
    LIST_FOREACH_SAFE(ks, &psm->pubSubKeyList, keyStorageList, ksTmp) {
        UA_PubSubKeyStorage_delete(psm, ks);
    }
#endif

    return UA_STATUSCODE_GOOD;
}

UA_ServerComponent *
UA_PubSubManager_new(UA_Server *server) {
    UA_PubSubManager *psm = (UA_PubSubManager*)UA_calloc(1, sizeof(UA_PubSubManager));
    if(!psm)
        return NULL;

    psm->sc.server = server;
    psm->sc.name = UA_STRING("pubsub");
    psm->sc.start = UA_PubSubManager_start;
    psm->sc.stop = UA_PubSubManager_stop;
    psm->sc.clear = (UA_StatusCode (*)(UA_ServerComponent *))UA_PubSubManager_clear;

    /* Set the logging shortcut */
    psm->logging = server->config.logging;

    /* TODO: Using the Mac address to generate the defaultPublisherId.
     * In the future, this can be retrieved from the Eventloop. */
    psm->defaultPublisherId = generateRandomUInt64();

    TAILQ_INIT(&psm->connections);
    TAILQ_INIT(&psm->publishedDataSets);
    TAILQ_INIT(&psm->subscribedDataSets);

#ifdef UA_ENABLE_PUBSUB_SKS
    TAILQ_INIT(&psm->securityGroups);
#endif

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    /* Build PubSub information model */
    initPubSubNS0(server);
#endif

    return &psm->sc;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_ns0.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2025 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019-2021 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020-2022 Thomas Fischer, Siemens AG
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 * Copyright (c) 2025 Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */

typedef struct {
    UA_NodeId parentNodeId;
    UA_UInt32 parentClassifier;
    UA_UInt32 elementClassiefier;
} UA_NodePropertyContext;

static UA_StatusCode
writePubSubNs0VariableArray(UA_Server *server, const UA_NodeId id, void *v,
                            size_t length, const UA_DataType *type) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setArray(&var, v, length, type);
    return writeValueAttribute(server, id, &var);
}

static UA_NodeId
findSingleChildNode(UA_Server *server, UA_QualifiedName targetName,
                    UA_NodeId referenceTypeId, UA_NodeId startingNode){
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_NodeId resultNodeId;
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = referenceTypeId;
    rpe.isInverse = false;
    rpe.includeSubtypes = false;
    rpe.targetName = targetName;
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = startingNode;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.statusCode != UA_STATUSCODE_GOOD ||
       bpr.targetsSize < 1)
        return UA_NODEID_NULL;
    UA_StatusCode res = UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId);
    if(res != UA_STATUSCODE_GOOD){
        UA_BrowsePathResult_clear(&bpr);
        return UA_NODEID_NULL;
    }
    UA_BrowsePathResult_clear(&bpr);
    return resultNodeId;
}

static UA_StatusCode
findPubSubComponentFromStatus(UA_Server *server, const UA_NodeId *statusObjectId,
                              UA_NodeId *componentNodeId, UA_PubSubComponentType *componentType,
                              void **component, UA_Boolean *isPublishSubscribeObject) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    *isPublishSubscribeObject = false;
    /* Find the parent PubSub component by browsing up from the Status object */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *statusObjectId;
    bd.browseDirection = UA_BROWSEDIRECTION_INVERSE;
    bd.referenceTypeId = UA_NS0ID(HASCOMPONENT);
    bd.includeSubtypes = false;
    bd.nodeClassMask = UA_NODECLASS_OBJECT;
    bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_TYPEDEFINITION;

    UA_BrowseResult br = UA_Server_browse(server, 0, &bd);
    if(br.statusCode != UA_STATUSCODE_GOOD || br.referencesSize == 0) {
        UA_BrowseResult_clear(&br);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    *componentNodeId = br.references[0].nodeId.nodeId;
    UA_NodeId parentTypeId = br.references[0].typeDefinition.nodeId;
    UA_BrowseResult_clear(&br);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Identify component type and find the component */
    UA_NodeId pubsubconnectionTypeId = UA_NS0ID(PUBSUBCONNECTIONTYPE);
    UA_NodeId writergroupTypeId = UA_NS0ID(WRITERGROUPTYPE);
    UA_NodeId readergroupTypeId = UA_NS0ID(READERGROUPTYPE);
    UA_NodeId datasetreaderTypeId = UA_NS0ID(DATASETREADERTYPE);
    UA_NodeId datasetwriterTypeId = UA_NS0ID(DATASETWRITERTYPE);
    UA_NodeId publishsubscribeTypeId = UA_NS0ID(PUBLISHSUBSCRIBETYPE);

    if(UA_NodeId_equal(&parentTypeId, &publishsubscribeTypeId)) {
        *isPublishSubscribeObject = true;
        *componentType = UA_PUBSUBCOMPONENT_CONNECTION;
        *component = psm;
        return UA_STATUSCODE_GOOD;
    } else if(UA_NodeId_equal(&parentTypeId, &pubsubconnectionTypeId)) {
        *componentType = UA_PUBSUBCOMPONENT_CONNECTION;
        *component = UA_PubSubConnection_find(psm, *componentNodeId);
    } else if(UA_NodeId_equal(&parentTypeId, &writergroupTypeId)) {
        *componentType = UA_PUBSUBCOMPONENT_WRITERGROUP;
        *component = UA_WriterGroup_find(psm, *componentNodeId);
    } else if(UA_NodeId_equal(&parentTypeId, &readergroupTypeId)) {
        *componentType = UA_PUBSUBCOMPONENT_READERGROUP;
        *component = UA_ReaderGroup_find(psm, *componentNodeId);
    } else if(UA_NodeId_equal(&parentTypeId, &datasetreaderTypeId)) {
        *componentType = UA_PUBSUBCOMPONENT_DATASETREADER;
        *component = UA_DataSetReader_find(psm, *componentNodeId);
    } else if(UA_NodeId_equal(&parentTypeId, &datasetwriterTypeId)) {
        *componentType = UA_PUBSUBCOMPONENT_DATASETWRITER;
        *component = UA_DataSetWriter_find(psm, *componentNodeId);
    } else {
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    if(!*component)
        return UA_STATUSCODE_BADNOTFOUND;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
pubSubStateVariableDataSourceRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                                  const UA_NodeId *nodeid, void *context, UA_Boolean includeSourceTimeStamp,
                                  const UA_NumericRange *range, UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Find the parent Status object by browsing inverse from State variable */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *nodeid;
    bd.browseDirection = UA_BROWSEDIRECTION_INVERSE;
    bd.referenceTypeId = UA_NS0ID(HASCOMPONENT);
    bd.includeSubtypes = false;
    bd.nodeClassMask = UA_NODECLASS_OBJECT;
    bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID;

    UA_BrowseResult br = UA_Server_browse(server, 0, &bd);
    if(br.statusCode != UA_STATUSCODE_GOOD || br.referencesSize == 0) {
        UA_BrowseResult_clear(&br);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_NodeId statusObjectId = br.references[0].nodeId.nodeId;
    UA_BrowseResult_clear(&br);

    UA_NodeId componentNodeId;
    UA_PubSubComponentType componentType;
    void *component = NULL;
    UA_Boolean isPublishSubscribeObject = false;
    
    UA_StatusCode retVal = findPubSubComponentFromStatus(server, &statusObjectId,
                                                        &componentNodeId, &componentType, &component, &isPublishSubscribeObject);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    UA_PubSubState state = UA_PUBSUBSTATE_DISABLED;
    
    if(isPublishSubscribeObject) {
        UA_PubSubManager *psm = (UA_PubSubManager*)component;
        state = (psm->sc.state == UA_LIFECYCLESTATE_STARTED) ? 
                UA_PUBSUBSTATE_OPERATIONAL : UA_PUBSUBSTATE_DISABLED;
    } else {
        switch(componentType) {
        case UA_PUBSUBCOMPONENT_CONNECTION:
            state = ((UA_PubSubConnection*)component)->head.state;
            break;
        case UA_PUBSUBCOMPONENT_WRITERGROUP:
            state = ((UA_WriterGroup*)component)->head.state;
            break;
        case UA_PUBSUBCOMPONENT_READERGROUP:
            state = ((UA_ReaderGroup*)component)->head.state;
            break;
        case UA_PUBSUBCOMPONENT_DATASETREADER:
            state = ((UA_DataSetReader*)component)->head.state;
            break;
        case UA_PUBSUBCOMPONENT_DATASETWRITER:
            state = ((UA_DataSetWriter*)component)->head.state;
            break;
        default:
            return UA_STATUSCODE_BADNOTSUPPORTED;
        }
    }

    value->hasValue = true;
    return UA_Variant_setScalarCopy(&value->value, &state, &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
}

static UA_StatusCode
enablePubSubObjectAction(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                         const UA_NodeId *methodId, void *methodContext,
                         const UA_NodeId *objectId, void *objectContext,
                         size_t inputSize, const UA_Variant *input,
                         size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Find the State variable within the Status object */
    UA_NodeId stateNodeId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                               UA_NS0ID(HASCOMPONENT), *objectId);
    if(UA_NodeId_isNull(&stateNodeId))
        return UA_STATUSCODE_BADNOTFOUND;

    /* Use helper function to identify and find the PubSub component */
    UA_NodeId componentNodeId;
    UA_PubSubComponentType componentType;
    void *component = NULL;
    UA_Boolean isPublishSubscribeObject = false;
    
    UA_StatusCode retVal = findPubSubComponentFromStatus(server, objectId,
                                                        &componentNodeId, &componentType, &component, &isPublishSubscribeObject);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(isPublishSubscribeObject) {
        if(psm->sc.state != UA_LIFECYCLESTATE_STOPPED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        UA_PubSubManager_setState(psm, UA_LIFECYCLESTATE_STARTED);
        return UA_STATUSCODE_GOOD;
    }

    switch(componentType) {
    case UA_PUBSUBCOMPONENT_CONNECTION: {
        UA_PubSubConnection *conn = (UA_PubSubConnection*)component;
        /* OPC UA Standard: "The Server shall reject Enable Method calls if the current State is not Disabled." */
        if(conn->head.state != UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_PubSubConnection_setPubSubState(psm, conn, UA_PUBSUBSTATE_OPERATIONAL);
        break;
    }
    case UA_PUBSUBCOMPONENT_WRITERGROUP: {
        UA_WriterGroup *wg = (UA_WriterGroup*)component;
        if(wg->head.state != UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_OPERATIONAL);
        break;
    }
    case UA_PUBSUBCOMPONENT_READERGROUP: {
        UA_ReaderGroup *rg = (UA_ReaderGroup*)component;
        if(rg->head.state != UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_OPERATIONAL);
        break;
    }
    case UA_PUBSUBCOMPONENT_DATASETREADER: {
        UA_DataSetReader *dsr = (UA_DataSetReader*)component;
        if(dsr->head.state != UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_OPERATIONAL, UA_STATUSCODE_GOOD);
        break;
    }
    case UA_PUBSUBCOMPONENT_DATASETWRITER: {
        UA_DataSetWriter *dsw = (UA_DataSetWriter*)component;
        if(dsw->head.state != UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_OPERATIONAL);
        break;
    }
    default:
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    return retVal;
}

static UA_StatusCode
disablePubSubObjectAction(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Find the State variable within the Status object */
    UA_NodeId stateNodeId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                               UA_NS0ID(HASCOMPONENT), *objectId);
    if(UA_NodeId_isNull(&stateNodeId))
        return UA_STATUSCODE_BADNOTFOUND;

    /* Use helper function to identify and find the PubSub component */
    UA_NodeId componentNodeId;
    UA_PubSubComponentType componentType;
    void *component = NULL;
    UA_Boolean isPublishSubscribeObject = false;
    
    UA_StatusCode retVal = findPubSubComponentFromStatus(server, objectId,
                                                        &componentNodeId, &componentType, &component, &isPublishSubscribeObject);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Handle PublishSubscribe object separately */
    if(isPublishSubscribeObject) {
        /* For PublishSubscribe object, check PubSubManager lifecycle state */
        if(psm->sc.state == UA_LIFECYCLESTATE_STOPPED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        /* Disable the PubSubManager by stopping it */
        UA_PubSubManager_setState(psm, UA_LIFECYCLESTATE_STOPPED);
        return UA_STATUSCODE_GOOD;
    }

    /* Disable the appropriate PubSub component with state validation */
    switch(componentType) {
    case UA_PUBSUBCOMPONENT_CONNECTION: {
        UA_PubSubConnection *conn = (UA_PubSubConnection*)component;
        /* OPC UA Standard: "The Server shall reject Disable Method calls if the current State is Disabled." */
        if(conn->head.state == UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_PubSubConnection_setPubSubState(psm, conn, UA_PUBSUBSTATE_DISABLED);
        break;
    }
    case UA_PUBSUBCOMPONENT_WRITERGROUP: {
        UA_WriterGroup *wg = (UA_WriterGroup*)component;
        if(wg->head.state == UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_DISABLED);
        break;
    }
    case UA_PUBSUBCOMPONENT_READERGROUP: {
        UA_ReaderGroup *rg = (UA_ReaderGroup*)component;
        if(rg->head.state == UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED);
        break;
    }
    case UA_PUBSUBCOMPONENT_DATASETREADER: {
        UA_DataSetReader *dsr = (UA_DataSetReader*)component;
        if(dsr->head.state == UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_DISABLED, UA_STATUSCODE_GOOD);
        break;
    }
    case UA_PUBSUBCOMPONENT_DATASETWRITER: {
        UA_DataSetWriter *dsw = (UA_DataSetWriter*)component;
        if(dsw->head.state == UA_PUBSUBSTATE_DISABLED)
            return UA_STATUSCODE_BADINVALIDSTATE;
        retVal = UA_DataSetWriter_setPubSubState(psm, dsw, UA_PUBSUBSTATE_DISABLED);
        break;
    }
    default:
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    return retVal;
}

static UA_StatusCode
ReadCallback(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
             const UA_NodeId *nodeid, void *context, UA_Boolean includeSourceTimeStamp,
             const UA_NumericRange *range, UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    const UA_NodePropertyContext *nodeContext = (const UA_NodePropertyContext*)context;
    const UA_NodeId *myNodeId = &nodeContext->parentNodeId;

    switch(nodeContext->parentClassifier) {
    case UA_NS0ID_PUBSUBCONNECTIONTYPE: {
        UA_PubSubConnection *pubSubConnection = UA_PubSubConnection_find(psm, *myNodeId);
        if(!pubSubConnection)
            return UA_STATUSCODE_BADNOTFOUND;
        if(nodeContext->elementClassiefier == UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID) {
            UA_Variant tmp;
            UA_PublisherId_toVariant(&pubSubConnection->config.publisherId, &tmp);
            value->hasValue = true;
            return UA_Variant_copy(&tmp, &value->value);
        }
        break;
    }
    case UA_NS0ID_READERGROUPTYPE: {
        UA_ReaderGroup *readerGroup = UA_ReaderGroup_find(psm, *myNodeId);
        if(!readerGroup)
            return UA_STATUSCODE_BADNOTFOUND;
        if(nodeContext->elementClassiefier == UA_NS0ID_PUBSUBGROUPTYPE_STATUS_STATE) {
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &readerGroup->head.state,
                                            &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
        }
        break;
    }
    case UA_NS0ID_DATASETREADERTYPE: {
        UA_DataSetReader *dataSetReader = UA_DataSetReader_find(psm, *myNodeId);
        if(!dataSetReader)
            return UA_STATUSCODE_BADNOTFOUND;
        switch(nodeContext->elementClassiefier) {
        case UA_NS0ID_DATASETREADERTYPE_PUBLISHERID: {
            UA_Variant tmp;
            UA_PublisherId_toVariant(&dataSetReader->config.publisherId, &tmp);
            value->hasValue = true;
            return UA_Variant_copy(&tmp, &value->value);
        }
        case UA_NS0ID_DATASETREADERTYPE_STATUS_STATE:
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &dataSetReader->head.state,
                                            &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
        default: break;
        }
        break;
    }
    case UA_NS0ID_WRITERGROUPTYPE: {
        UA_WriterGroup *writerGroup = UA_WriterGroup_find(psm, *myNodeId);
        if(!writerGroup)
            return UA_STATUSCODE_BADNOTFOUND;
        switch(nodeContext->elementClassiefier){
        case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value,
                                            &writerGroup->config.publishingInterval,
                                            &UA_TYPES[UA_TYPES_DURATION]);
            break;
        case UA_NS0ID_PUBSUBGROUPTYPE_STATUS_STATE:
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &writerGroup->head.state,
                                            &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
            break;
        default: break;
        }
        break;
    }
    case UA_NS0ID_DATASETWRITERTYPE: {
        UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_find(psm, *myNodeId);
        if(!dataSetWriter)
            return UA_STATUSCODE_BADNOTFOUND;
        switch(nodeContext->elementClassiefier) {
        case UA_NS0ID_DATASETWRITERTYPE_DATASETWRITERID:
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &dataSetWriter->config.dataSetWriterId,
                                            &UA_TYPES[UA_TYPES_UINT16]);
        case UA_NS0ID_DATASETWRITERTYPE_STATUS_STATE:
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &dataSetWriter->head.state,
                                            &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
        default: break;
        }
        break;
    }
    case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
        UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_find(psm, *myNodeId);
        if(!publishedDataSet)
            return UA_STATUSCODE_BADNOTFOUND;
        switch(nodeContext->elementClassiefier) {
        case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
            UA_PublishedVariableDataType *pvd = (UA_PublishedVariableDataType *)
                UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
            size_t counter = 0;
            UA_DataSetField *field;
            TAILQ_FOREACH(field, &publishedDataSet->fields, listEntry) {
                pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
                pvd[counter].publishedVariable =
                    field->config.field.variable.publishParameters.publishedVariable;
                UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable,
                               &pvd[counter].publishedVariable);
                counter++;
            }
            value->hasValue = true;
            UA_Variant_setArray(&value->value, pvd, publishedDataSet->fieldSize,
                                &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
            return UA_STATUSCODE_GOOD;
        }
        case UA_NS0ID_PUBLISHEDDATASETTYPE_DATASETMETADATA:
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &publishedDataSet->dataSetMetaData,
                                            &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
        case UA_NS0ID_PUBLISHEDDATASETTYPE_CONFIGURATIONVERSION:
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value,
                                            &publishedDataSet->dataSetMetaData.configurationVersion,
                                            &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
        default: break;
        }
        break;
    }
    case UA_NS0ID_STANDALONESUBSCRIBEDDATASETREFDATATYPE: {
        UA_SubscribedDataSet *sds = UA_SubscribedDataSet_find(psm, *myNodeId);
        if(!sds)
            return UA_STATUSCODE_BADNOTFOUND;
        switch(nodeContext->elementClassiefier) {
        case UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_ISCONNECTED: {
            UA_Boolean isConnected = (sds->connectedReader != NULL);
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &isConnected,
                                            &UA_TYPES[UA_TYPES_BOOLEAN]);
        }
        case UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_DATASETMETADATA: {
            value->hasValue = true;
            return UA_Variant_setScalarCopy(&value->value, &sds->config.dataSetMetaData,
                                            &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
        }
        default: break;
        }
        break;
    }
    default: break;
    }

    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                   "Read error! Unknown property");
    return UA_STATUSCODE_BADINTERNALERROR;
}

static UA_StatusCode
WriteCallback(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
              const UA_NodeId *nodeId, void *nodeContext,
              const UA_NumericRange *range, const UA_DataValue *data) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodePropertyContext *npc = (UA_NodePropertyContext *)nodeContext;

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADNOTFOUND;

    UA_WriterGroup *writerGroup = NULL;
    UA_StatusCode res = UA_STATUSCODE_BADNOTWRITABLE;
    switch(npc->parentClassifier) {
    case UA_NS0ID_PUBSUBCONNECTIONTYPE:
        break;
    case UA_NS0ID_WRITERGROUPTYPE: {
        writerGroup = UA_WriterGroup_find(psm, npc->parentNodeId);
        if(!writerGroup)
            return UA_STATUSCODE_BADNOTFOUND;
        switch(npc->elementClassiefier) {
        case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL: {
            if(!UA_Variant_hasScalarType(&data->value, &UA_TYPES[UA_TYPES_DURATION]) &&
               !UA_Variant_hasScalarType(&data->value, &UA_TYPES[UA_TYPES_DOUBLE]))
                return UA_STATUSCODE_BADTYPEMISMATCH;
            UA_Duration interval = *((UA_Duration *) data->value.data);
            if(interval <= 0.0)
                return UA_STATUSCODE_BADOUTOFRANGE;
            writerGroup->config.publishingInterval = interval;
            if(writerGroup->head.state == UA_PUBSUBSTATE_OPERATIONAL) {
                UA_WriterGroup_removePublishCallback(psm, writerGroup);
                UA_WriterGroup_addPublishCallback(psm, writerGroup);
            }
            return UA_STATUSCODE_GOOD;
        }
        default: break;
        }
        break;
    }
    default: break;
    }

    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                   "Changing the ReaderGroupConfig failed");
    return res;
}

static UA_StatusCode
setVariableValueSource(UA_Server *server, const UA_CallbackValueSource evs,
                       UA_NodeId node, UA_NodePropertyContext *context){
    UA_LOCK_ASSERT(&server->serviceMutex);
    setNodeContext(server, node, context);
    return setVariableNode_callbackValueSource(server, node, evs);
}

static UA_StatusCode
addPubSubConnectionConfig(UA_Server *server, UA_PubSubConnectionDataType *pubsubConnection,
                          UA_NodeId *connectionId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_NetworkAddressUrlDataType networkAddressUrl;
    memset(&networkAddressUrl, 0, sizeof(networkAddressUrl));
    UA_ExtensionObject *eo = &pubsubConnection->address;
    if(eo->encoding == UA_EXTENSIONOBJECT_DECODED &&
       eo->content.decoded.type == &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]) {
        void *data = eo->content.decoded.data;
        retVal =
            UA_NetworkAddressUrlDataType_copy((UA_NetworkAddressUrlDataType *)data,
                                              &networkAddressUrl);
        if(retVal != UA_STATUSCODE_GOOD)
            return retVal;
    }

    UA_PubSubConnectionConfig connectionConfig;
    memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
    connectionConfig.transportProfileUri = pubsubConnection->transportProfileUri;
    connectionConfig.name = pubsubConnection->name;
    UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl,
                         &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);

    retVal |= UA_PublisherId_fromVariant(&connectionConfig.publisherId,
                                         &pubsubConnection->publisherId);
    retVal |= UA_PubSubConnection_create(psm, &connectionConfig, connectionId);
    UA_NetworkAddressUrlDataType_clear(&networkAddressUrl);
    return retVal;
}

/**
 * **WriterGroup handling**
 *
 * The WriterGroup (WG) is part of the connection and contains the primary
 * configuration parameters for the message creation. */
static UA_StatusCode
addWriterGroupConfig(UA_Server *server, UA_NodeId connectionId,
                     UA_WriterGroupDataType *writerGroup, UA_NodeId *writerGroupId){
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Now we create a new WriterGroupConfig and add the group to the existing
     * PubSubConnection. */
    UA_WriterGroupConfig writerGroupConfig;
    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
    writerGroupConfig.name = writerGroup->name;
    writerGroupConfig.publishingInterval = writerGroup->publishingInterval;
    writerGroupConfig.writerGroupId = writerGroup->writerGroupId;
    writerGroupConfig.priority = writerGroup->priority;

    UA_ExtensionObject *eoWG = &writerGroup->messageSettings;
    UA_UadpWriterGroupMessageDataType uadpWriterGroupMessage;
    UA_JsonWriterGroupMessageDataType jsonWriterGroupMessage;
    if(eoWG->encoding == UA_EXTENSIONOBJECT_DECODED){
        writerGroupConfig.messageSettings.encoding  = UA_EXTENSIONOBJECT_DECODED;
        if(eoWG->content.decoded.type == &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]){
            writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
            if(UA_UadpWriterGroupMessageDataType_copy(
                    (UA_UadpWriterGroupMessageDataType *)eoWG->content.decoded.data,
                    &uadpWriterGroupMessage) != UA_STATUSCODE_GOOD) {
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
            writerGroupConfig.messageSettings.content.decoded.data = &uadpWriterGroupMessage;
        } else if(eoWG->content.decoded.type == &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE]) {
            writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_JSON;
            if(UA_JsonWriterGroupMessageDataType_copy(
                   (UA_JsonWriterGroupMessageDataType *)eoWG->content.decoded.data,
                   &jsonWriterGroupMessage) != UA_STATUSCODE_GOOD) {
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE];
            writerGroupConfig.messageSettings.content.decoded.data = &jsonWriterGroupMessage;
        }
    }

    eoWG = &writerGroup->transportSettings;
    UA_BrokerWriterGroupTransportDataType brokerWriterGroupTransport;
    UA_DatagramWriterGroupTransportDataType datagramWriterGroupTransport;
    if(eoWG->encoding == UA_EXTENSIONOBJECT_DECODED) {
        writerGroupConfig.transportSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
        if(eoWG->content.decoded.type == &UA_TYPES[UA_TYPES_BROKERWRITERGROUPTRANSPORTDATATYPE]) {
            if(UA_BrokerWriterGroupTransportDataType_copy(
                    (UA_BrokerWriterGroupTransportDataType*)eoWG->content.decoded.data,
                    &brokerWriterGroupTransport) != UA_STATUSCODE_GOOD) {
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            writerGroupConfig.transportSettings.content.decoded.type = &UA_TYPES[UA_TYPES_BROKERWRITERGROUPTRANSPORTDATATYPE];
            writerGroupConfig.transportSettings.content.decoded.data = &brokerWriterGroupTransport;
        } else if(eoWG->content.decoded.type == &UA_TYPES[UA_TYPES_DATAGRAMWRITERGROUPTRANSPORTDATATYPE]) {
            if(UA_DatagramWriterGroupTransportDataType_copy(
                   (UA_DatagramWriterGroupTransportDataType *)eoWG->content.decoded.data,
                   &datagramWriterGroupTransport) != UA_STATUSCODE_GOOD) {
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            writerGroupConfig.transportSettings.content.decoded.type = &UA_TYPES[UA_TYPES_DATAGRAMWRITERGROUPTRANSPORTDATATYPE];
            writerGroupConfig.transportSettings.content.decoded.data = &datagramWriterGroupTransport;
        }
    }
    if (writerGroupConfig.encodingMimeType == UA_PUBSUB_ENCODING_JSON
        && (writerGroupConfig.transportSettings.encoding != UA_EXTENSIONOBJECT_DECODED ||
        writerGroupConfig.transportSettings.content.decoded.type !=
            &UA_TYPES[UA_TYPES_BROKERWRITERGROUPTRANSPORTDATATYPE])) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "JSON encoding is supported only for MQTT transport");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    return UA_WriterGroup_create(psm, connectionId, &writerGroupConfig, writerGroupId);
}

/**
 * **DataSetWriter handling**
 *
 * A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is
 * linked to exactly one PDS and contains additional informations for the
 * message generation. */
static UA_StatusCode
addDataSetWriterConfig(UA_Server *server, const UA_NodeId *writerGroupId,
                       UA_DataSetWriterDataType *dataSetWriter,
                       UA_NodeId *dataSetWriterId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_NodeId publishedDataSetId = UA_NODEID_NULL;
    UA_PublishedDataSet *tmpPDS;
    TAILQ_FOREACH(tmpPDS, &psm->publishedDataSets, listEntry){
        if(UA_String_equal(&dataSetWriter->dataSetName, &tmpPDS->config.name)) {
            publishedDataSetId = tmpPDS->head.identifier;
            break;
        }
    }

    if(UA_NodeId_isNull(&publishedDataSetId))
        return UA_STATUSCODE_BADPARENTNODEIDINVALID;

    /* We need now a DataSetWriter within the WriterGroup. This means we must
     * create a new DataSetWriterConfig and add call the addWriterGroup function. */
    UA_DataSetWriterConfig dataSetWriterConfig;
    memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
    dataSetWriterConfig.name = dataSetWriter->name;
    dataSetWriterConfig.dataSetWriterId = dataSetWriter->dataSetWriterId;
    dataSetWriterConfig.keyFrameCount = dataSetWriter->keyFrameCount;
    dataSetWriterConfig.dataSetFieldContentMask =  dataSetWriter->dataSetFieldContentMask;
    return UA_DataSetWriter_create(psm, *writerGroupId, publishedDataSetId,
                                   &dataSetWriterConfig, dataSetWriterId);
}

/**
 * **ReaderGroup**
 *
 * ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are
 * created within a PubSubConnection and automatically deleted if the connection
 * is removed. All network message related filters are only available in the DataSetReader. */
/* Add ReaderGroup to the created connection */
static UA_StatusCode
addReaderGroupConfig(UA_Server *server, UA_NodeId connectionId,
                     UA_ReaderGroupDataType *readerGroup,
                     UA_NodeId *readerGroupId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ReaderGroupConfig readerGroupConfig;
    memset(&readerGroupConfig, 0, sizeof(UA_ReaderGroupConfig));
    readerGroupConfig.name = readerGroup->name;
    return UA_ReaderGroup_create(psm, connectionId,
                                 &readerGroupConfig, readerGroupId);
}

/**
 * **SubscribedDataSet**
 *
 * Set SubscribedDataSet type to TargetVariables data type.
 * Add subscribedvariables to the DataSetReader */
static UA_StatusCode
addSubscribedVariables(UA_Server *server, UA_NodeId dataSetReaderId,
                       UA_DataSetReaderDataType *dataSetReader,
                       UA_DataSetMetaDataType *pMetaData) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ExtensionObject *eoTargetVar = &dataSetReader->subscribedDataSet;
    if(eoTargetVar->encoding != UA_EXTENSIONOBJECT_DECODED ||
       eoTargetVar->content.decoded.type != &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE])
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    const UA_TargetVariablesDataType *targetVars =
        (UA_TargetVariablesDataType*)eoTargetVar->content.decoded.data;

    UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dataSetReaderId);
    if(!dsr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_NodeId folderId;
    UA_String folderName = pMetaData->name;
    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
    UA_QualifiedName folderBrowseName;
    if(folderName.length > 0) {
        oAttr.displayName.locale = UA_STRING("");
        oAttr.displayName.text = folderName;
        folderBrowseName.namespaceIndex = 1;
        folderBrowseName.name = folderName;
    } else {
        oAttr.displayName = UA_LOCALIZEDTEXT("", "Subscribed Variables");
        folderBrowseName = UA_QUALIFIEDNAME(1, "Subscribed Variables");
    }

    addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NULL,
            UA_NS0ID(OBJECTSFOLDER), UA_NS0ID(ORGANIZES),
            folderBrowseName, UA_NS0ID(BASEOBJECTTYPE),
            &oAttr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
            NULL, &folderId);

    /* The SubscribedDataSet option TargetVariables defines a list of Variable
     * mappings between received DataSet fields and target Variables in the
     * Subscriber AddressSpace. The values subscribed from the Publisher are
     * updated in the value field of these variables */

    /* Add variable for the fields */
    for(size_t i = 0; i < targetVars->targetVariablesSize; i++) {
        UA_VariableAttributes vAttr = UA_VariableAttributes_default;
        vAttr.description = pMetaData->fields[i].description;
        vAttr.displayName.locale = UA_STRING("");
        vAttr.displayName.text = pMetaData->fields[i].name;
        vAttr.dataType = pMetaData->fields[i].dataType;
        UA_QualifiedName varname = {1, pMetaData->fields[i].name};
        addNode(server, UA_NODECLASS_VARIABLE,
                targetVars->targetVariables[i].targetNodeId, folderId,
                UA_NS0ID(HASCOMPONENT), varname, UA_NS0ID(BASEDATAVARIABLETYPE),
                &vAttr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                NULL, &targetVars->targetVariables[i].targetNodeId);
    }

    /* Set the TargetVariables in the DSR config */
    return DataSetReader_createTargetVariables(psm, dsr,
                                               targetVars->targetVariablesSize,
                                               targetVars->targetVariables);
}

/**
 * **DataSetReader**
 *
 * DataSetReader can receive NetworkMessages with the DataSetMessage
 * of interest sent by the Publisher. DataSetReader provides
 * the configuration necessary to receive and process DataSetMessages
 * on the Subscriber side. DataSetReader must be linked with a
 * SubscribedDataSet and be contained within a ReaderGroup. */
static UA_StatusCode
addDataSetReaderConfig(UA_Server *server, UA_NodeId readerGroupId,
                       UA_DataSetReaderDataType *dataSetReader,
                       UA_NodeId *dataSetReaderId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_DataSetReaderConfig readerConfig;
    memset(&readerConfig, 0, sizeof(UA_DataSetReaderConfig));

    UA_StatusCode retVal =
        UA_PublisherId_fromVariant(&readerConfig.publisherId,
                                   &dataSetReader->publisherId);
    readerConfig.name = dataSetReader->name;
    readerConfig.writerGroupId = dataSetReader->writerGroupId;
    readerConfig.dataSetWriterId = dataSetReader->dataSetWriterId;

    /* Setting up Meta data configuration in DataSetReader */
    UA_DataSetMetaDataType *pMetaData;
    pMetaData = &readerConfig.dataSetMetaData;
    UA_DataSetMetaDataType_init (pMetaData);
    pMetaData->name =  dataSetReader->dataSetMetaData.name;
    pMetaData->fieldsSize = dataSetReader->dataSetMetaData.fieldsSize;
    pMetaData->fields = (UA_FieldMetaData*)UA_Array_new (pMetaData->fieldsSize,
                        &UA_TYPES[UA_TYPES_FIELDMETADATA]);
    if(pMetaData->fieldsSize > 0 && !pMetaData->fields) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                     "Failed to allocate memory for DataSetReader MetaData fields");
        UA_PublisherId_clear(&readerConfig.publisherId);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    for(size_t i = 0; i < pMetaData->fieldsSize; i++){
        UA_FieldMetaData_init (&pMetaData->fields[i]);
        UA_NodeId_copy(&dataSetReader->dataSetMetaData.fields[i].dataType,
                       &pMetaData->fields[i].dataType);
        pMetaData->fields[i].builtInType = dataSetReader->dataSetMetaData.fields[i].builtInType;
        pMetaData->fields[i].name = dataSetReader->dataSetMetaData.fields[i].name;
        pMetaData->fields[i].valueRank = dataSetReader->dataSetMetaData.fields[i].valueRank;
    }

    retVal |= UA_DataSetReader_create(psm, readerGroupId,
                                      &readerConfig, dataSetReaderId);
    UA_PublisherId_clear(&readerConfig.publisherId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_free(pMetaData->fields);
        return retVal;
    }

    retVal |= addSubscribedVariables(server, *dataSetReaderId, dataSetReader, pMetaData);
    UA_free(pMetaData->fields);
    return retVal;
}

/*************************************************/
/*            PubSubConnection                   */
/*************************************************/

UA_StatusCode
addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection) {
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(connection->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    char connectionName[513];
    memcpy(connectionName, connection->config.name.data, connection->config.name.length);
    connectionName[connection->config.name.length] = '\0';

    UA_ObjectAttributes attr = UA_ObjectAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT("", connectionName);
    retVal |= addNode_begin(server, UA_NODECLASS_OBJECT,
                            UA_NODEID_NUMERIC(1, 0), /* Generate a new id */
                            UA_NS0ID(PUBLISHSUBSCRIBE),
                            UA_NS0ID(HASPUBSUBCONNECTION),
                            UA_QUALIFIEDNAME(0, connectionName),
                            UA_NS0ID(PUBSUBCONNECTIONTYPE),
                            (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                            NULL, &connection->head.identifier);

    attr.displayName = UA_LOCALIZEDTEXT("", "Address");
    retVal |= addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0),
                      connection->head.identifier, UA_NS0ID(HASCOMPONENT),
                      UA_QUALIFIEDNAME(0, "Address"), UA_NS0ID(NETWORKADDRESSURLTYPE),
                      &attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, NULL);

    retVal |= addNode_finish(server, &server->adminSession, &connection->head.identifier);

    UA_NodeId addressNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"),
                            UA_NS0ID(HASCOMPONENT), connection->head.identifier);
    UA_NodeId urlNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Url"),
                            UA_NS0ID(HASCOMPONENT), addressNode);
    UA_NodeId interfaceNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkInterface"),
                            UA_NS0ID(HASCOMPONENT), addressNode);
    UA_NodeId publisherIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                            UA_NS0ID(HASPROPERTY), connection->head.identifier);
    UA_NodeId connectionPropertyNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConnectionProperties"),
                            UA_NS0ID(HASPROPERTY), connection->head.identifier);
    UA_NodeId transportProfileUri =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "TransportProfileUri"),
                            UA_NS0ID(HASCOMPONENT), connection->head.identifier);
    UA_NodeId statusIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                            UA_NS0ID(HASCOMPONENT), connection->head.identifier);

    if(UA_NodeId_isNull(&addressNode) || UA_NodeId_isNull(&urlNode) ||
       UA_NodeId_isNull(&interfaceNode) || UA_NodeId_isNull(&publisherIdNode) ||
       UA_NodeId_isNull(&connectionPropertyNode) ||
       UA_NodeId_isNull(&transportProfileUri)) {
        return UA_STATUSCODE_BADNOTFOUND;
    }

    retVal |= writePubSubNs0VariableArray(server, connectionPropertyNode,
                                          connection->config.connectionProperties.map,
                                          connection->config.connectionProperties.mapSize,
                                          &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);

    UA_NetworkAddressUrlDataType *networkAddressUrl=
        ((UA_NetworkAddressUrlDataType*)connection->config.address.data);
    UA_Variant value;
    UA_Variant_init(&value);

    UA_Variant_setScalar(&value, &networkAddressUrl->url, &UA_TYPES[UA_TYPES_STRING]);
    writeValueAttribute(server, urlNode, &value);

    UA_Variant_setScalar(&value, &networkAddressUrl->networkInterface, &UA_TYPES[UA_TYPES_STRING]);
    writeValueAttribute(server, interfaceNode, &value);

    UA_Variant_setScalar(&value, &connection->config.transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
    writeValueAttribute(server, transportProfileUri, &value);

    UA_NodePropertyContext *connectionPublisherIdContext =
        (UA_NodePropertyContext *)UA_malloc(sizeof(UA_NodePropertyContext));
    connectionPublisherIdContext->parentNodeId = connection->head.identifier;
    connectionPublisherIdContext->parentClassifier = UA_NS0ID_PUBSUBCONNECTIONTYPE;
    connectionPublisherIdContext->elementClassiefier = UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID;

    UA_CallbackValueSource valueCallback;
    valueCallback.read = ReadCallback;
    valueCallback.write = NULL;
    retVal |= setVariableValueSource(server, valueCallback, publisherIdNode,
                                     connectionPublisherIdContext);

    if(!UA_NodeId_isNull(&statusIdNode)) {
        UA_NodeId stateNodeId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                                   UA_NS0ID(HASCOMPONENT), statusIdNode);
        if(!UA_NodeId_isNull(&stateNodeId)) {
            UA_DataSource stateDataSource;
            stateDataSource.read = pubSubStateVariableDataSourceRead;
            stateDataSource.write = NULL;
            retVal |= UA_Server_setVariableNode_dataSource(server, stateNodeId, stateDataSource);
        }
    }

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, connection->head.identifier, UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), true);
        retVal |= addRef(server, connection->head.identifier, UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(PUBSUBCONNECTIONTYPE_ADDREADERGROUP), true);
        retVal |= addRef(server, connection->head.identifier, UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(PUBSUBCONNECTIONTYPE_REMOVEGROUP), true);
        
        if(!UA_NodeId_isNull(&statusIdNode)) {
            retVal |= addRef(server, statusIdNode,
                            UA_NS0ID(HASCOMPONENT),
                            UA_NS0ID(PUBSUBSTATUSTYPE_ENABLE), true);
            retVal |= addRef(server, statusIdNode,
                            UA_NS0ID(HASCOMPONENT),
                            UA_NS0ID(PUBSUBSTATUSTYPE_DISABLE), true);
        }
    }
    return retVal;
}

static UA_StatusCode
addPubSubConnectionAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_PubSubConnectionDataType *pubSubConnection =
        (UA_PubSubConnectionDataType *) input[0].data;

    //call API function and create the connection
    UA_NodeId connectionId;
    retVal |= addPubSubConnectionConfig(server, pubSubConnection, &connectionId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "addPubSubConnection failed");
        return retVal;
    }

    for(size_t i = 0; i < pubSubConnection->writerGroupsSize; i++) {
        UA_NodeId writerGroupId;
        UA_WriterGroupDataType *writerGroup = &pubSubConnection->writerGroups[i];
        retVal |= addWriterGroupConfig(server, connectionId, writerGroup, &writerGroupId);
        if(retVal != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "addWriterGroup failed");
            return retVal;
        }

        for(size_t j = 0; j < writerGroup->dataSetWritersSize; j++) {
            UA_DataSetWriterDataType *dataSetWriter = &writerGroup->dataSetWriters[j];
            retVal |= addDataSetWriterConfig(server, &writerGroupId, dataSetWriter, NULL);
            if(retVal != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "addDataSetWriter failed");
                return retVal;
            }
        }

        /* TODO: Need to handle the UA_Server_setWriterGroupOperational based on
         * the status variable in information model */
        UA_WriterGroup *wg = UA_WriterGroup_find(psm, writerGroupId);
        if(!wg)
            continue;
        if(pubSubConnection->enabled) {
            UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_OPERATIONAL);
        } else {
            UA_WriterGroup_setPubSubState(psm, wg, UA_PUBSUBSTATE_DISABLED);
        }
    }

    for(size_t i = 0; i < pubSubConnection->readerGroupsSize; i++){
        UA_NodeId readerGroupId;
        UA_ReaderGroupDataType *readerGroup = &pubSubConnection->readerGroups[i];
        retVal |= addReaderGroupConfig(server, connectionId, readerGroup, &readerGroupId);
        if(retVal != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "addReaderGroup failed");
            return retVal;
        }

        for(size_t j = 0; j < readerGroup->dataSetReadersSize; j++) {
            UA_NodeId dataSetReaderId;
            UA_DataSetReaderDataType *dataSetReader = &readerGroup->dataSetReaders[j];
            retVal |= addDataSetReaderConfig(server, readerGroupId,
                                             dataSetReader, &dataSetReaderId);
            if(retVal != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "addDataSetReader failed");
                return retVal;
            }

        }

        /* TODO: Need to handle the UA_Server_setReaderGroupOperational based on
         * the status variable in information model */
        UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupId);
        if(!rg)
            continue;
        if(pubSubConnection->enabled) {
            UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_OPERATIONAL);
        } else {
            UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED);
        }
    }

    /* Set ouput value */
    UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removeConnectionAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output){
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    retVal |= UA_Server_removePubSubConnection(server, nodeToRemove);
    if(retVal == UA_STATUSCODE_BADNOTFOUND)
        retVal = UA_STATUSCODE_BADNODEIDUNKNOWN;
    return retVal;
}

/**********************************************/
/*               DataSetReader                */
/**********************************************/

UA_StatusCode
addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader){
    UA_LOCK_ASSERT(&server->serviceMutex);

    if(dataSetReader->config.name.length > 512)
        return UA_STATUSCODE_BADCONFIGURATIONERROR;

    char dsrName[513];
    memcpy(dsrName, dataSetReader->config.name.data, dataSetReader->config.name.length);
    dsrName[dataSetReader->config.name.length] = '\0';

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_NodeId publisherIdNode, writerGroupIdNode, dataSetwriterIdNode, statusIdNode, stateIdNode;

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", dsrName);
    retVal = addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* create an id */
                     dataSetReader->linkedReaderGroup->head.identifier,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASDATASETREADER),
                     UA_QUALIFIEDNAME(0, dsrName),
                     UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERTYPE),
                     &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                     NULL, &dataSetReader->head.identifier);

    /* Add childNodes such as PublisherId, WriterGroupId and DataSetWriterId in
     * DataSetReader object */
    publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                          dataSetReader->head.identifier);
    writerGroupIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
                                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                            dataSetReader->head.identifier);
    dataSetwriterIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"),
                                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                              dataSetReader->head.identifier);
    statusIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                              dataSetReader->head.identifier);

    if(UA_NodeId_isNull(&statusIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    stateIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                              statusIdNode);

    if(UA_NodeId_isNull(&publisherIdNode) ||
       UA_NodeId_isNull(&writerGroupIdNode) ||
       UA_NodeId_isNull(&dataSetwriterIdNode) ||
       UA_NodeId_isNull(&stateIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext *dataSetReaderPublisherIdContext =
        (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
    dataSetReaderPublisherIdContext->parentNodeId = dataSetReader->head.identifier;
    dataSetReaderPublisherIdContext->parentClassifier = UA_NS0ID_DATASETREADERTYPE;
    dataSetReaderPublisherIdContext->elementClassiefier = UA_NS0ID_DATASETREADERTYPE_PUBLISHERID;
    UA_CallbackValueSource valueCallback;
    valueCallback.read = ReadCallback;
    valueCallback.write = NULL;
    retVal |= setVariableValueSource(server, valueCallback, publisherIdNode,
                                     dataSetReaderPublisherIdContext);

    UA_NodeId stateNodeId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                               UA_NS0ID(HASCOMPONENT), statusIdNode);
    if(!UA_NodeId_isNull(&stateNodeId)) {
        UA_DataSource stateDataSource;
        stateDataSource.read = pubSubStateVariableDataSourceRead;
        stateDataSource.write = NULL; 
        retVal |= UA_Server_setVariableNode_dataSource(server, stateNodeId, stateDataSource);
    }

    /* Update childNode with values from Publisher */
    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &dataSetReader->config.writerGroupId,
                         &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, writerGroupIdNode, &value);
    UA_Variant_setScalar(&value, &dataSetReader->config.dataSetWriterId,
                         &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, dataSetwriterIdNode, &value);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_ENABLE), true);
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_DISABLE), true);
    }
    
    return retVal;
}

static UA_StatusCode
addDataSetReaderAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId dataSetReaderId;
    UA_DataSetReaderDataType *dataSetReader= (UA_DataSetReaderDataType *) input[0].data;
    UA_StatusCode retVal =
        addDataSetReaderConfig(server, *objectId, dataSetReader, &dataSetReaderId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "AddDataSetReader failed");
        return retVal;
    }

    UA_Variant_setScalarCopy(output, &dataSetReaderId, &UA_TYPES[UA_TYPES_NODEID]);
    return retVal;
}

static UA_StatusCode
removeDataSetReaderAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output){
    UA_NodeId nodeToRemove = *((UA_NodeId *)input[0].data);
    return UA_Server_removeDataSetReader(server, nodeToRemove);
}

/*************************************************/
/*                PublishedDataSet               */
/*************************************************/

static UA_StatusCode
addDataSetFolderAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output){
    /* defined in R 1.04 9.1.4.5.7 */
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_String newFolderName = *((UA_String *) input[0].data);
    UA_NodeId generatedId;
    UA_ObjectAttributes objectAttributes = UA_ObjectAttributes_default;
    UA_LocalizedText name = {UA_STRING(""), newFolderName};
    objectAttributes.displayName = name;
    retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId,
                                      UA_NS0ID(ORGANIZES),
                                      UA_QUALIFIEDNAME(0, "DataSetFolder"),
                                      UA_NS0ID(DATASETFOLDERTYPE),
                                      objectAttributes, NULL, &generatedId);
    UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= UA_Server_addReference(server, generatedId, UA_NS0ID(HASCOMPONENT),
                                         UA_NS0EXID(DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
        retVal |= UA_Server_addReference(server, generatedId, UA_NS0ID(HASCOMPONENT),
                                         UA_NS0EXID(DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
        retVal |= UA_Server_addReference(server, generatedId, UA_NS0ID(HASCOMPONENT),
                                         UA_NS0EXID(DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
        retVal |= UA_Server_addReference(server, generatedId, UA_NS0ID(HASCOMPONENT),
                                         UA_NS0EXID(DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
    }
    return retVal;
}

static UA_StatusCode
removeDataSetFolderAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    return UA_Server_deleteNode(server, nodeToRemove, true);
}

UA_StatusCode
addPublishedDataItemsRepresentation(UA_Server *server,
                                    UA_PublishedDataSet *publishedDataSet) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(publishedDataSet->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    char pdsName[513];
    memcpy(pdsName, publishedDataSet->config.name.data, publishedDataSet->config.name.length);
    pdsName[publishedDataSet->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", pdsName);
    retVal = addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* Create a new id */
                     UA_NS0ID(PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                     UA_NS0ID(HASCOMPONENT),
                     UA_QUALIFIEDNAME(0, pdsName),
                     UA_NS0ID(PUBLISHEDDATAITEMSTYPE),
                     &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                     NULL, &publishedDataSet->head.identifier);
    UA_CHECK_STATUS(retVal, return retVal);

    UA_CallbackValueSource valueCallback;
    valueCallback.read = ReadCallback;
    valueCallback.write = NULL;
    //ToDo: Need to move the browse name from namespaceindex 0 to 1
    UA_NodeId configurationVersionNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
                            UA_NS0ID(HASPROPERTY), publishedDataSet->head.identifier);
    if(UA_NodeId_isNull(&configurationVersionNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext *configurationVersionContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    configurationVersionContext->parentNodeId = publishedDataSet->head.identifier;
    configurationVersionContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
    configurationVersionContext->elementClassiefier =
        UA_NS0ID_PUBLISHEDDATASETTYPE_CONFIGURATIONVERSION;
    retVal |= setVariableValueSource(server, valueCallback, configurationVersionNode,
                                     configurationVersionContext);

    UA_NodeId publishedDataNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
                            UA_NS0ID(HASPROPERTY), publishedDataSet->head.identifier);
    if(UA_NodeId_isNull(&publishedDataNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    publishingIntervalContext->parentNodeId = publishedDataSet->head.identifier;
    publishingIntervalContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
    publishingIntervalContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA;
    retVal |= setVariableValueSource(server, valueCallback, publishedDataNode,
                                     publishingIntervalContext);

    UA_NodeId dataSetMetaDataNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NS0ID(HASPROPERTY), publishedDataSet->head.identifier);
    if(UA_NodeId_isNull(&dataSetMetaDataNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    metaDataContext->parentNodeId = publishedDataSet->head.identifier;
    metaDataContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
    metaDataContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATASETTYPE_DATASETMETADATA;
    retVal |= setVariableValueSource(server, valueCallback,
                                     dataSetMetaDataNode, metaDataContext);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, publishedDataSet->head.identifier, UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), true);
        retVal |= addRef(server, publishedDataSet->head.identifier, UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), true);
    }
    return retVal;
}

static UA_StatusCode
addPublishedDataItemsAction(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *methodId, void *methodContext,
                            const UA_NodeId *objectId, void *objectContext,
                            size_t inputSize, const UA_Variant *input,
                            size_t outputSize, UA_Variant *output){
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    size_t fieldNameAliasesSize = input[1].arrayLength;
    UA_String * fieldNameAliases = (UA_String *) input[1].data;
    size_t fieldFlagsSize = input[2].arrayLength;
    UA_DataSetFieldFlags * fieldFlags = (UA_DataSetFieldFlags *) input[2].data;
    size_t variablesToAddSize = input[3].arrayLength;
    UA_PublishedVariableDataType *eoAddVar =
        (UA_PublishedVariableDataType *)input[3].data;

    if(fieldNameAliasesSize != fieldFlagsSize ||
       fieldFlagsSize != variablesToAddSize)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_PublishedDataSetConfig publishedDataSetConfig;
    memset(&publishedDataSetConfig, 0, sizeof(publishedDataSetConfig));
    publishedDataSetConfig.name = *((UA_String *) input[0].data);
    publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;

    UA_NodeId dataSetItemsNodeId;
    retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig,
                                            &dataSetItemsNodeId).addResult;
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "addPublishedDataset failed");
        return retVal;
    }

    UA_DataSetFieldConfig dataSetFieldConfig;
    for(size_t j = 0; j < variablesToAddSize; ++j) {
        /* Prepare the config */
        memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig));
        dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
        dataSetFieldConfig.field.variable.fieldNameAlias = fieldNameAliases[j];
        dataSetFieldConfig.field.variable.publishParameters = eoAddVar[j];
        if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD)
            dataSetFieldConfig.field.variable.promotedField = true;
        retVal |= UA_Server_addDataSetField(server, dataSetItemsNodeId,
                                            &dataSetFieldConfig, NULL).result;
        if(retVal != UA_STATUSCODE_GOOD) {
           UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                        "addDataSetField failed");
           return retVal;
        }
    }

    UA_Variant_setScalarCopy(output, &dataSetItemsNodeId, &UA_TYPES[UA_TYPES_NODEID]);
    return retVal;
}

static UA_StatusCode
addVariablesAction(UA_Server *server,
                   const UA_NodeId *sessionId, void *sessionContext,
                   const UA_NodeId *methodId, void *methodContext,
                   const UA_NodeId *objectId, void *objectContext,
                   size_t inputSize, const UA_Variant *input,
                   size_t outputSize, UA_Variant *output){
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removeVariablesAction(UA_Server *server,
                      const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext,
                      size_t inputSize, const UA_Variant *input,
                      size_t outputSize, UA_Variant *output){
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removePublishedDataSetAction(UA_Server *server,
                             const UA_NodeId *sessionId, void *sessionContext,
                             const UA_NodeId *methodId, void *methodContext,
                             const UA_NodeId *objectId, void *objectContext,
                             size_t inputSize, const UA_Variant *input,
                             size_t outputSize, UA_Variant *output){
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    return UA_Server_removePublishedDataSet(server, nodeToRemove);
}

/*********************/
/* SubscribedDataSet */
/*********************/

UA_StatusCode
addSubscribedDataSetRepresentation(UA_Server *server,
                                   UA_SubscribedDataSet *subscribedDataSet) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(subscribedDataSet->config.name.length > 512)
        return UA_STATUSCODE_BADCONFIGURATIONERROR;

    UA_STACKARRAY(char, sdsName, sizeof(char) * subscribedDataSet->config.name.length +1);
    memcpy(sdsName, subscribedDataSet->config.name.data, subscribedDataSet->config.name.length);
    sdsName[subscribedDataSet->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", sdsName);
    addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* Create a new id */
            UA_NS0ID(PUBLISHSUBSCRIBE_SUBSCRIBEDDATASETS),
            UA_NS0ID(HASCOMPONENT),
            UA_QUALIFIEDNAME(0, sdsName),
            UA_NS0ID(STANDALONESUBSCRIBEDDATASETTYPE),
            &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
            NULL, &subscribedDataSet->head.identifier);
    UA_NodeId sdsObjectNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "SubscribedDataSet"),
                            UA_NS0ID(HASCOMPONENT), subscribedDataSet->head.identifier);
    UA_NodeId metaDataId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NS0ID(HASPROPERTY), subscribedDataSet->head.identifier);
    UA_NodeId connectedId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "IsConnected"),
                            UA_NS0ID(HASPROPERTY), subscribedDataSet->head.identifier);

    if(UA_NodeId_equal(&sdsObjectNode, &UA_NODEID_NULL) ||
       UA_NodeId_equal(&metaDataId, &UA_NODEID_NULL) ||
       UA_NodeId_equal(&connectedId, &UA_NODEID_NULL)) {
        return UA_STATUSCODE_BADNOTFOUND;
    }
    if(subscribedDataSet->config.subscribedDataSetType == UA_PUBSUB_SDS_TARGET){
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        UA_NodeId targetVarsId;
        attr.displayName = UA_LOCALIZEDTEXT("", "TargetVariables");
        attr.dataType = UA_TYPES[UA_TYPES_FIELDTARGETDATATYPE].typeId;
        attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
        attr.arrayDimensionsSize = 1;
        UA_UInt32 arrayDimensions[1];
        arrayDimensions[0] = (UA_UInt32)
            subscribedDataSet->config.subscribedDataSet.target.targetVariablesSize;
        attr.arrayDimensions = arrayDimensions;
        attr.accessLevel = UA_ACCESSLEVELMASK_READ;
        UA_Variant_setArray(&attr.value,
                            subscribedDataSet->config.subscribedDataSet.target.targetVariables,
                            subscribedDataSet->config.subscribedDataSet.target.targetVariablesSize,
                            &UA_TYPES[UA_TYPES_FIELDTARGETDATATYPE]);
        ret |= addNode(server, UA_NODECLASS_VARIABLE, UA_NODEID_NULL, sdsObjectNode,
                       UA_NS0ID(HASPROPERTY), UA_QUALIFIEDNAME(0, "TargetVariables"),
                       UA_NS0ID(PROPERTYTYPE), &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                       NULL, &targetVarsId);
    }

    UA_NodePropertyContext *isConnectedNodeContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    isConnectedNodeContext->parentNodeId = subscribedDataSet->head.identifier;
    isConnectedNodeContext->parentClassifier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETREFDATATYPE;
    isConnectedNodeContext->elementClassiefier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_ISCONNECTED;

    UA_CallbackValueSource valueCallback;
    valueCallback.read = ReadCallback;
    valueCallback.write = NULL;
    ret |= setVariableValueSource(server, valueCallback, connectedId, isConnectedNodeContext);

    UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    metaDataContext->parentNodeId = subscribedDataSet->head.identifier;
    metaDataContext->parentClassifier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETREFDATATYPE;
    metaDataContext->elementClassiefier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_DATASETMETADATA;
    ret |= setVariableValueSource(server, valueCallback, metaDataId, metaDataContext);

    return ret;
}

/**********************************************/
/*               WriterGroup                  */
/**********************************************/

static UA_StatusCode
readContentMask(UA_Server *server, const UA_NodeId *sessionId,
                void *sessionContext, const UA_NodeId *nodeId,
                void *nodeContext, UA_Boolean includeSourceTimeStamp,
                const UA_NumericRange *range, UA_DataValue *value) {
    UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
    if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
        writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       writerGroup->config.messageSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
        writerGroup->config.messageSettings.content.decoded.data;

    UA_Variant_setScalarCopy(&value->value, &wgm->networkMessageContentMask,
                             &UA_TYPES[UA_TYPES_UADPNETWORKMESSAGECONTENTMASK]);
    value->hasValue = true;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeContentMask(UA_Server *server, const UA_NodeId *sessionId,
                 void *sessionContext, const UA_NodeId *nodeId,
                 void *nodeContext, const UA_NumericRange *range,
                 const UA_DataValue *value) {
    UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
    if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
        writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       writerGroup->config.messageSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
        writerGroup->config.messageSettings.content.decoded.data;

    if(!value->value.type)
        return UA_STATUSCODE_BADTYPEMISMATCH;
    if(value->value.type->typeKind != UA_DATATYPEKIND_ENUM &&
       value->value.type->typeKind != UA_DATATYPEKIND_INT32)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    wgm->networkMessageContentMask = *(UA_UadpNetworkMessageContentMask*)value->value.data;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readGroupVersion(UA_Server *server, const UA_NodeId *sessionId,
                void *sessionContext, const UA_NodeId *nodeId,
                void *nodeContext, UA_Boolean includeSourceTimeStamp,
                const UA_NumericRange *range, UA_DataValue *value) {
    UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
    if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
        writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       writerGroup->config.messageSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
        writerGroup->config.messageSettings.content.decoded.data;

    UA_Variant_setScalarCopy(&value->value, &wgm->groupVersion,
                             &UA_TYPES[UA_DATATYPEKIND_UINT32]);
    value->hasValue = true;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(writerGroup->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    char wgName[513];
    memcpy(wgName, writerGroup->config.name.data, writerGroup->config.name.length);
    wgName[writerGroup->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", wgName);
    retVal = addNode(server, UA_NODECLASS_OBJECT,
                     UA_NODEID_NUMERIC(1, 0), /* create a new id */
                     writerGroup->linkedConnection->head.identifier, UA_NS0ID(HASCOMPONENT),
                     UA_QUALIFIEDNAME(0, wgName), UA_NS0ID(WRITERGROUPTYPE), &object_attr,
                     &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, &writerGroup->head.identifier);

    UA_NodeId keepAliveNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeepAliveTime"),
                            UA_NS0ID(HASPROPERTY), writerGroup->head.identifier);
    UA_NodeId publishingIntervalNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
                            UA_NS0ID(HASPROPERTY), writerGroup->head.identifier);
    UA_NodeId statusIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                            UA_NS0ID(HASCOMPONENT), writerGroup->head.identifier);

    if(UA_NodeId_isNull(&statusIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodeId stateIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                            UA_NS0ID(HASCOMPONENT), statusIdNode);

    if(UA_NodeId_isNull(&keepAliveNode) ||
       UA_NodeId_isNull(&publishingIntervalNode) ||
       UA_NodeId_isNull(&stateIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    publishingIntervalContext->parentNodeId = writerGroup->head.identifier;
    publishingIntervalContext->parentClassifier = UA_NS0ID_WRITERGROUPTYPE;
    publishingIntervalContext->elementClassiefier = UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL;
    UA_CallbackValueSource valueCallback;
    valueCallback.read = ReadCallback;
    valueCallback.write = WriteCallback;
    retVal |= setVariableValueSource(server, valueCallback,
                                     publishingIntervalNode, publishingIntervalContext);
    writeAccessLevelAttribute(server, publishingIntervalNode,
                              UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE);

    UA_NodeId stateNodeId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                               UA_NS0ID(HASCOMPONENT), statusIdNode);
    if(!UA_NodeId_isNull(&stateNodeId)) {
        UA_DataSource stateDataSource;
        stateDataSource.read = pubSubStateVariableDataSourceRead;
        stateDataSource.write = NULL;
        retVal |= UA_Server_setVariableNode_dataSource(server, stateNodeId, stateDataSource);
    }

    UA_NodeId priorityNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"),
                            UA_NS0ID(HASPROPERTY), writerGroup->head.identifier);
    UA_NodeId writerGroupIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
                            UA_NS0ID(HASPROPERTY), writerGroup->head.identifier);

    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]);
    writeValueAttribute(server, publishingIntervalNode, &value);
    UA_Variant_setScalar(&value, &writerGroup->config.keepAliveTime, &UA_TYPES[UA_TYPES_DURATION]);
    writeValueAttribute(server, keepAliveNode, &value);
    UA_Variant_setScalar(&value, &writerGroup->config.priority, &UA_TYPES[UA_TYPES_BYTE]);
    writeValueAttribute(server, priorityNode, &value);
    UA_Variant_setScalar(&value, &writerGroup->config.writerGroupId, &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, writerGroupIdNode, &value);

    object_attr.displayName = UA_LOCALIZEDTEXT("", "MessageSettings");
    retVal |= addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0),
                      writerGroup->head.identifier, UA_NS0ID(HASCOMPONENT),
                      UA_QUALIFIEDNAME(0, "MessageSettings"),
                      UA_NS0ID(UADPWRITERGROUPMESSAGETYPE), &object_attr,
                      &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                      NULL, NULL);

    /* Find the variable with the content mask */

    UA_NodeId messageSettingsId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "MessageSettings"),
                            UA_NS0ID(HASCOMPONENT), writerGroup->head.identifier);
    UA_NodeId contentMaskId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkMessageContentMask"),
                            UA_NS0ID(HASPROPERTY), messageSettingsId);
    if(!UA_NodeId_isNull(&contentMaskId)) {
        /* Set the callback */
        UA_CallbackValueSource ds;
        ds.read = readContentMask;
        ds.write = writeContentMask;
        setVariableNode_callbackValueSource(server, contentMaskId, ds);
        setNodeContext(server, contentMaskId, writerGroup);

        /* Make writable */
        writeAccessLevelAttribute(server, contentMaskId,
                                  UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_READ);

    }
    UA_NodeId groupVersionId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "GroupVersion"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), messageSettingsId);
    if(!UA_NodeId_isNull(&groupVersionId)) {
        /* Set the callback */
        UA_CallbackValueSource ds;
        ds.read = readGroupVersion;
        ds.write = NULL;
        setVariableNode_callbackValueSource(server, groupVersionId, ds);
        setNodeContext(server, groupVersionId, writerGroup);

        /* Read only */
        writeAccessLevelAttribute(server, groupVersionId,
                                  UA_ACCESSLEVELMASK_READ);

    }

    /* Add reference to methods */
    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, writerGroup->head.identifier,
                         UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(WRITERGROUPTYPE_ADDDATASETWRITER), true);
        retVal |= addRef(server, writerGroup->head.identifier,
                         UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(WRITERGROUPTYPE_REMOVEDATASETWRITER), true);
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_ENABLE), true);
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_DISABLE), true);
    }
    return retVal;
}

static UA_StatusCode
addWriterGroupAction(UA_Server *server,
                     const UA_NodeId *sessionId, void *sessionContext,
                     const UA_NodeId *methodId, void *methodContext,
                     const UA_NodeId *objectId, void *objectContext,
                     size_t inputSize, const UA_Variant *input,
                     size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId writerGroupId;
    UA_WriterGroupDataType *writerGroup = (UA_WriterGroupDataType *)input->data;
    UA_StatusCode retVal = addWriterGroupConfig(server, *objectId, writerGroup, &writerGroupId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "addWriterGroup failed");
        return retVal;
    }
    // TODO: Need to handle the UA_Server_setWriterGroupOperational based on the
    // status variable in information model

    UA_Variant_setScalarCopy(output, &writerGroupId, &UA_TYPES[UA_TYPES_NODEID]);
    return retVal;
}

static UA_StatusCode
removeGroupAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionContext,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output){
    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_NodeId nodeToRemove = *((UA_NodeId *)input->data);
    if(UA_WriterGroup_find(psm, nodeToRemove)) {
        return UA_Server_removeWriterGroup(server, nodeToRemove);
    } else {
        return UA_Server_removeReaderGroup(server, nodeToRemove);
    }
}

/**********************************************/
/*               ReserveIds                   */
/**********************************************/

static UA_StatusCode
addReserveIdsAction(UA_Server *server,
                    const UA_NodeId *sessionId, void *sessionContext,
                    const UA_NodeId *methodId, void *methodContext,
                    const UA_NodeId *objectId, void *objectContext,
                    size_t inputSize, const UA_Variant *input,
                    size_t outputSize, UA_Variant *output){
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_String transportProfileUri = *((UA_String *)input[0].data);
    UA_UInt16 numRegWriterGroupIds = *((UA_UInt16 *)input[1].data);
    UA_UInt16 numRegDataSetWriterIds = *((UA_UInt16 *)input[2].data);

    UA_UInt16 *writerGroupIds;
    UA_UInt16 *dataSetWriterIds;

    retVal |= UA_PubSubManager_reserveIds(psm, *sessionId, numRegWriterGroupIds,
                                          numRegDataSetWriterIds, transportProfileUri,
                                          &writerGroupIds, &dataSetWriterIds);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "addReserveIds failed");
        return retVal;
    }

    /* Check the transportProfileUri */
    UA_String profile_1 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp");
    UA_String profile_2 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json");

    if(UA_String_equal(&transportProfileUri, &profile_1) ||
       UA_String_equal(&transportProfileUri, &profile_2)) {
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER, "ApplicationUri: %S",
                    server->config.applicationDescription.applicationUri);
        retVal |= UA_Variant_setScalarCopy(&output[0],
                                           &server->config.applicationDescription.applicationUri,
                                           &UA_TYPES[UA_TYPES_STRING]);
    } else {
        retVal |= UA_Variant_setScalarCopy(&output[0], &psm->defaultPublisherId,
                                           &UA_TYPES[UA_TYPES_UINT64]);
    }

    UA_Variant_setArray(&output[1], writerGroupIds,
                        numRegWriterGroupIds, &UA_TYPES[UA_TYPES_UINT16]);
    UA_Variant_setArray(&output[2], dataSetWriterIds,
                        numRegDataSetWriterIds, &UA_TYPES[UA_TYPES_UINT16]);

    return retVal;
}

/**********************************************/
/*               ReaderGroup                  */
/**********************************************/

UA_StatusCode
addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    if(readerGroup->config.name.length > 512)
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    char rgName[513];
    memcpy(rgName, readerGroup->config.name.data, readerGroup->config.name.length);
    rgName[readerGroup->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", rgName);
    UA_StatusCode retVal =
        addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* create an id */
                readerGroup->linkedConnection->head.identifier,
                UA_NS0ID(HASCOMPONENT),
                UA_QUALIFIEDNAME(0, rgName), UA_NS0ID(READERGROUPTYPE),
                &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                NULL, &readerGroup->head.identifier);

    UA_NodeId statusIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                            UA_NS0ID(HASCOMPONENT), readerGroup->head.identifier);

    if(UA_NodeId_isNull(&statusIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodeId stateIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                            UA_NS0ID(HASCOMPONENT), statusIdNode);

    if(UA_NodeId_isNull(&stateIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_DataSource stateDataSource;
    stateDataSource.read = pubSubStateVariableDataSourceRead;
    stateDataSource.write = NULL;
    retVal |= UA_Server_setVariableNode_dataSource(server, stateIdNode, stateDataSource);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, readerGroup->head.identifier, UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(READERGROUPTYPE_ADDDATASETREADER), true);
        retVal |= addRef(server, readerGroup->head.identifier, UA_NS0ID(HASCOMPONENT),
                         UA_NS0ID(READERGROUPTYPE_REMOVEDATASETREADER), true);
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_ENABLE), true);
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_DISABLE), true);
    }
    return retVal;
}

static UA_StatusCode
addReaderGroupAction(UA_Server *server,
                     const UA_NodeId *sessionId, void *sessionContext,
                     const UA_NodeId *methodId, void *methodContext,
                     const UA_NodeId *objectId, void *objectContext,
                     size_t inputSize, const UA_Variant *input,
                     size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_ReaderGroupDataType *readerGroup = ((UA_ReaderGroupDataType *) input->data);
    UA_NodeId readerGroupId;
    retVal |= addReaderGroupConfig(server, *objectId, readerGroup, &readerGroupId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "addReaderGroup failed");
        return retVal;
    }
    // TODO: Need to handle the UA_Server_setReaderGroupOperational based on the
    // status variable in information model

    UA_Variant_setScalarCopy(output, &readerGroupId, &UA_TYPES[UA_TYPES_NODEID]);
    return retVal;
}

/**********************************************/
/*               DataSetWriter                */
/**********************************************/

UA_StatusCode
addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter) {

    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(dataSetWriter->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    char dswName[513];
    memcpy(dswName, dataSetWriter->config.name.data, dataSetWriter->config.name.length);
    dswName[dataSetWriter->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", dswName);
    retVal =
        addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* create an id */
                dataSetWriter->linkedWriterGroup->head.identifier, UA_NS0ID(HASDATASETWRITER),
                UA_QUALIFIEDNAME(0, dswName), UA_NS0ID(DATASETWRITERTYPE), &object_attr,
                &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                     NULL, &dataSetWriter->head.identifier);
    //if connected dataset is null this means it's configured for heartbeats
    if(dataSetWriter->connectedDataSet) {
        retVal |= addRef(server, dataSetWriter->connectedDataSet->head.identifier,
                         UA_NS0ID(DATASETTOWRITER), dataSetWriter->head.identifier, true);
    }

    UA_NodeId dataSetWriterIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"),
                            UA_NS0ID(HASPROPERTY), dataSetWriter->head.identifier);
    UA_NodeId keyFrameNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeyFrameCount"),
                            UA_NS0ID(HASPROPERTY), dataSetWriter->head.identifier);
    UA_NodeId dataSetFieldContentMaskNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetFieldContentMask"),
                            UA_NS0ID(HASPROPERTY), dataSetWriter->head.identifier);

    UA_NodeId statusIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                            UA_NS0ID(HASCOMPONENT), dataSetWriter->head.identifier);
    
    if(UA_NodeId_isNull(&statusIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodeId stateIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                            UA_NS0ID(HASCOMPONENT), statusIdNode);

    // TODO: The keyFrameNode is NULL here, should be check
    // does not depend on the pubsub changes
    if(UA_NodeId_isNull(&dataSetWriterIdNode) ||
       UA_NodeId_isNull(&dataSetFieldContentMaskNode) ||
       UA_NodeId_isNull(&stateIdNode))
            return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext *dataSetWriterIdContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    dataSetWriterIdContext->parentNodeId = dataSetWriter->head.identifier;
    dataSetWriterIdContext->parentClassifier = UA_NS0ID_DATASETWRITERTYPE;
    dataSetWriterIdContext->elementClassiefier = UA_NS0ID_DATASETWRITERTYPE_DATASETWRITERID;
    UA_CallbackValueSource valueCallback;
    valueCallback.read = ReadCallback;
    valueCallback.write = NULL;
    retVal |= setVariableValueSource(server, valueCallback,
                                     dataSetWriterIdNode, dataSetWriterIdContext);

    UA_NodeId stateNodeId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                               UA_NS0ID(HASCOMPONENT), statusIdNode);
    if(!UA_NodeId_isNull(&stateNodeId)) {
        UA_DataSource stateDataSource;
        stateDataSource.read = pubSubStateVariableDataSourceRead;
        stateDataSource.write = NULL;
        retVal |= UA_Server_setVariableNode_dataSource(server, stateNodeId, stateDataSource);
    }

    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetWriterId,
                         &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, dataSetWriterIdNode, &value);

    UA_Variant_setScalar(&value, &dataSetWriter->config.keyFrameCount,
                         &UA_TYPES[UA_TYPES_UINT32]);
    writeValueAttribute(server, keyFrameNode, &value);

    UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetFieldContentMask,
                         &UA_TYPES[UA_TYPES_DATASETFIELDCONTENTMASK]);
    writeValueAttribute(server, dataSetFieldContentMaskNode, &value);

    object_attr.displayName = UA_LOCALIZEDTEXT("", "MessageSettings");
    retVal |= addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0),
                      dataSetWriter->head.identifier, UA_NS0ID(HASCOMPONENT),
                      UA_QUALIFIEDNAME(0, "MessageSettings"),
                      UA_NS0ID(UADPDATASETWRITERMESSAGETYPE), &object_attr,
                      &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                      NULL, NULL);
    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_ENABLE), true);
        retVal |= addRef(server, statusIdNode, UA_NS0ID(HASCOMPONENT), 
                        UA_NS0ID(PUBSUBSTATUSTYPE_DISABLE), true);
    }

    return retVal;
}

static UA_StatusCode
addDataSetWriterAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId dataSetWriterId;
    UA_DataSetWriterDataType *dataSetWriterData = (UA_DataSetWriterDataType *)input->data;
    UA_StatusCode retVal =
        addDataSetWriterConfig(server, objectId, dataSetWriterData, &dataSetWriterId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "addDataSetWriter failed");
        return retVal;
    }

    UA_Variant_setScalarCopy(output, &dataSetWriterId, &UA_TYPES[UA_TYPES_NODEID]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removeDataSetWriterAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output){
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    return UA_Server_removeDataSetWriter(server, nodeToRemove);
}

/**********************************************/
/*                Destructors                 */
/**********************************************/

static void
connectionTypeDestructor(UA_Server *server,
                         const UA_NodeId *sessionId, void *sessionContext,
                         const UA_NodeId *typeId, void *typeContext,
                         const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                "Connection destructor called!");
    UA_NodeId publisherIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                            UA_NS0ID(HASPROPERTY), *nodeId);
    UA_NodePropertyContext *ctx;
    getNodeContext(server, publisherIdNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&publisherIdNode))
        UA_free(ctx);
}

static void
writerGroupTypeDestructor(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *typeId, void *typeContext,
                          const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                "WriterGroup destructor called!");
    UA_NodeId intervalNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
                            UA_NS0ID(HASPROPERTY), *nodeId);

    UA_NodePropertyContext *ctx;
    getNodeContext(server, intervalNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&intervalNode))
        UA_free(ctx);
}

static void
readerGroupTypeDestructor(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *typeId, void *typeContext,
                          const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK_ASSERT(&server->serviceMutex);
}

static void
dataSetWriterTypeDestructor(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *typeId, void *typeContext,
                            const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                "DataSetWriter destructor called!");

    UA_NodeId dataSetWriterIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"),
                            UA_NS0ID(HASPROPERTY), *nodeId);

    UA_NodePropertyContext *ctx;
    getNodeContext(server, dataSetWriterIdNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&dataSetWriterIdNode))
        UA_free(ctx);
}

static void
dataSetReaderTypeDestructor(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *typeId, void *typeContext,
                            const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                "DataSetReader destructor called!");
    UA_NodeId publisherIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                            UA_NS0ID(HASPROPERTY), *nodeId);

    UA_NodePropertyContext *ctx;
    getNodeContext(server, publisherIdNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&publisherIdNode))
        UA_free(ctx);
}

static void
publishedDataItemsTypeDestructor(UA_Server *server,
                                 const UA_NodeId *sessionId, void *sessionContext,
                                 const UA_NodeId *typeId, void *typeContext,
                                 const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                "PublishedDataItems destructor called!");
    void *childContext;
    UA_NodeId node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
                                         UA_NS0ID(HASPROPERTY), *nodeId);
    if(!UA_NodeId_isNull(&node)) {
        getNodeContext(server, node, (void**)&childContext);
        UA_free(childContext);
    }

    node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
                               UA_NS0ID(HASPROPERTY), *nodeId);
    if(!UA_NodeId_isNull(&node)) {
        getNodeContext(server, node, (void**)&childContext);
        UA_free(childContext);
    }

    node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                               UA_NS0ID(HASPROPERTY), *nodeId);
    if(!UA_NodeId_isNull(&node)) {
        getNodeContext(server, node, (void**)&childContext);
        UA_free(childContext);
    }
}

static void
subscribedDataSetTypeDestructor(UA_Server *server,
                                const UA_NodeId *sessionId, void *sessionContext,
                                const UA_NodeId *typeId, void *typeContext,
                                const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                "Standalone SubscribedDataSet destructor called!");
    void *childContext;
    UA_NodeId node =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NS0ID(HASPROPERTY), *nodeId);
    if(!UA_NodeId_isNull(&node)) {
        getNodeContext(server, node, (void**)&childContext);
        UA_free(childContext);
    }
    node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "IsConnected"),
                               UA_NS0ID(HASPROPERTY), *nodeId);
    if(!UA_NodeId_isNull(&node)) {
        getNodeContext(server, node, (void**)&childContext);
        UA_free(childContext);
    }
}

/*************************************/
/*         PubSub configurator       */
/*************************************/

#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG

/* Callback function that will be executed when the method "PubSub configurator
 * (replace config)" is called. */
static UA_StatusCode
UA_loadPubSubConfigMethodCallback(UA_Server *server,
                                  const UA_NodeId *sessionId, void *sessionContext,
                                  const UA_NodeId *methodId, void *methodContext,
                                  const UA_NodeId *objectId, void *objectContext,
                                  size_t inputSize, const UA_Variant *input,
                                  size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    if(inputSize == 1) {
        UA_ByteString *inputStr = (UA_ByteString*)input->data;
        return UA_Server_loadPubSubConfigFromByteString(server, *inputStr);
    } else if(inputSize > 1) {
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;
    } else {
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
}

static void
deletePubSubConfigMethodFinalize(void *application, void *context) {
    UA_PubSubManager *manager = (UA_PubSubManager *) application;
    UA_Server *server = manager->sc.server;
    lockServer(manager->sc.server);
    UA_PubSubManager_clear(manager);
    unlockServer(server);
    UA_free(context);
}

/* Callback function that will be executed when the method "PubSub configurator
 *  (delete config)" is called. */
static UA_StatusCode
UA_deletePubSubConfigMethodCallback(UA_Server *server,
                                    const UA_NodeId *sessionId, void *sessionContext,
                                    const UA_NodeId *methodId, void *methodContext,
                                    const UA_NodeId *objectId, void *objectContext,
                                    size_t inputSize, const UA_Variant *input,
                                    size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_PubSubManager *psm = getPSM(server);
    if(psm) {
        psm->sc.stop(&psm->sc);
        UA_DelayedCallback *dc = (UA_DelayedCallback*)UA_calloc(1, sizeof(UA_DelayedCallback));
        if(!dc)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        dc->callback = deletePubSubConfigMethodFinalize;
        dc->application = psm;
        dc->context = dc;
        server->config.eventLoop->addDelayedCallback(psm->sc.server->config.eventLoop, dc);
    }

    return UA_STATUSCODE_GOOD;
}

#endif

UA_StatusCode
initPubSubNS0(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_String profileArray[1];
    profileArray[0] = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");

    retVal |= writePubSubNs0VariableArray(server,
                                          UA_NS0ID(PUBLISHSUBSCRIBE_SUPPORTEDTRANSPORTPROFILES),
                                          profileArray, 1, &UA_TYPES[UA_TYPES_STRING]);

    /* Set read callback for PublishSubscribeType Status State (mandatory) */
    UA_CallbackValueSource statusCallback;
    statusCallback.read = pubSubStateVariableDataSourceRead;
    statusCallback.write = NULL;
    retVal |= setVariableValueSource(server, statusCallback, 
                                    UA_NS0ID(PUBLISHSUBSCRIBE_STATUS_STATE), NULL);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        /* Add missing references */
        retVal |= addRef(server, UA_NS0ID(PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NS0ID(HASCOMPONENT), UA_NS0ID(DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
        retVal |= addRef(server, UA_NS0ID(PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NS0ID(HASCOMPONENT), UA_NS0ID(DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
        retVal |= addRef(server, UA_NS0ID(PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NS0ID(HASCOMPONENT), UA_NS0ID(DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
        retVal |= addRef(server, UA_NS0ID(PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NS0ID(HASCOMPONENT), UA_NS0ID(DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
        retVal |= addRef(server, UA_NS0ID(PUBLISHSUBSCRIBE_STATUS),
                         UA_NS0ID(HASCOMPONENT), UA_NS0ID(PUBSUBSTATUSTYPE_ENABLE), true);
        retVal |= addRef(server, UA_NS0ID(PUBLISHSUBSCRIBE_STATUS),
                         UA_NS0ID(HASCOMPONENT), UA_NS0ID(PUBSUBSTATUSTYPE_DISABLE), true);

        /* Set method callbacks */
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), addVariablesAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), removeVariablesAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBSUBCONNECTIONTYPE_ADDREADERGROUP), addReaderGroupAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(WRITERGROUPTYPE_ADDDATASETWRITER), addDataSetWriterAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(WRITERGROUPTYPE_REMOVEDATASETWRITER), removeDataSetWriterAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(READERGROUPTYPE_ADDDATASETREADER), addDataSetReaderAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(READERGROUPTYPE_REMOVEDATASETREADER), removeDataSetReaderAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBLISHSUBSCRIBE_PUBSUBCONFIGURATION_RESERVEIDS), addReserveIdsAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBSUBSTATUSTYPE_ENABLE), enablePubSubObjectAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBSUBSTATUSTYPE_DISABLE), disablePubSubObjectAction);

#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG
        /* Adds method node to server. This method is used to load binary files for
         * PubSub configuration and delete / replace old PubSub configurations. */
        UA_Argument inputArgument;
        UA_Argument_init(&inputArgument);
        inputArgument.description = UA_LOCALIZEDTEXT("", "PubSub config binfile");
        inputArgument.name = UA_STRING("BinFile");
        inputArgument.dataType = UA_TYPES[UA_TYPES_BYTESTRING].typeId;
        inputArgument.valueRank = UA_VALUERANK_SCALAR;

        UA_MethodAttributes configAttr = UA_MethodAttributes_default;
        configAttr.description = UA_LOCALIZEDTEXT("","Load binary configuration file");
        configAttr.displayName = UA_LOCALIZEDTEXT("","LoadPubSubConfigurationFile");
        configAttr.executable = true;
        configAttr.userExecutable = true;
        retVal |= addMethodNode(server, UA_NODEID_NULL,
                                UA_NS0ID(PUBLISHSUBSCRIBE), UA_NS0ID(HASORDEREDCOMPONENT),
                                UA_QUALIFIEDNAME(1, "PubSub configuration"),
                                &configAttr, UA_loadPubSubConfigMethodCallback,
                                1, &inputArgument, UA_NODEID_NULL, NULL,
                                0, NULL, UA_NODEID_NULL, NULL,
                                NULL, NULL);

        /* Adds method node to server. This method is used to delete the current
         * PubSub configuration. */
        configAttr.description = UA_LOCALIZEDTEXT("","Delete current PubSub configuration");
        configAttr.displayName = UA_LOCALIZEDTEXT("","DeletePubSubConfiguration");
        configAttr.executable = true;
        configAttr.userExecutable = true;
        retVal |= addMethodNode(server, UA_NODEID_NULL,
                                UA_NS0ID(PUBLISHSUBSCRIBE), UA_NS0ID(HASORDEREDCOMPONENT),
                                UA_QUALIFIEDNAME(1, "Delete PubSub config"),
                                &configAttr, UA_deletePubSubConfigMethodCallback,
                                0, NULL, UA_NODEID_NULL, NULL,
                                0, NULL, UA_NODEID_NULL, NULL,
                                NULL, NULL);
#endif
    } else {
        /* Remove methods */
        retVal |= deleteReference(server, UA_NS0ID(PUBLISHSUBSCRIBE),
                                  UA_NS0ID(HASCOMPONENT), true,
                                  UA_NS0EXID(PUBLISHSUBSCRIBE_ADDCONNECTION), false);
        retVal |= deleteReference(server, UA_NS0ID(PUBLISHSUBSCRIBE),
                                  UA_NS0ID(HASCOMPONENT), true,
                                  UA_NS0EXID(PUBLISHSUBSCRIBE_REMOVECONNECTION), false);
    }

    /* Set the object-type destructors */
    UA_NodeTypeLifecycle lifeCycle;
    lifeCycle.constructor = NULL;

    lifeCycle.destructor = connectionTypeDestructor;
    retVal |= setNodeTypeLifecycle(server, UA_NS0ID(PUBSUBCONNECTIONTYPE), lifeCycle);

    lifeCycle.destructor = writerGroupTypeDestructor;
    retVal |= setNodeTypeLifecycle(server, UA_NS0ID(WRITERGROUPTYPE), lifeCycle);

    lifeCycle.destructor = readerGroupTypeDestructor;
    retVal |= setNodeTypeLifecycle(server, UA_NS0ID(READERGROUPTYPE), lifeCycle);

    lifeCycle.destructor = dataSetWriterTypeDestructor;
    retVal |= setNodeTypeLifecycle(server, UA_NS0ID(DATASETWRITERTYPE), lifeCycle);

    lifeCycle.destructor = publishedDataItemsTypeDestructor;
    retVal |= setNodeTypeLifecycle(server, UA_NS0ID(PUBLISHEDDATAITEMSTYPE), lifeCycle);

    lifeCycle.destructor = dataSetReaderTypeDestructor;
    retVal |= setNodeTypeLifecycle(server, UA_NS0ID(DATASETREADERTYPE), lifeCycle);

    lifeCycle.destructor = subscribedDataSetTypeDestructor;
    retVal |= setNodeTypeLifecycle(server, UA_NS0ID(STANDALONESUBSCRIBEDDATASETTYPE), lifeCycle);

#ifdef UA_ENABLE_PUBSUB_SKS
    /* Initialize SKS-specific functionality */
    retVal |= initPubSubNS0_SKS(server);
#endif

    return retVal;
}

/* Remove the Metadata nodes of the DSR and reference the Metadata nodes of the
 * SDS instead */
UA_StatusCode
connectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId, UA_NodeId sdsId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId dataSetMetaDataOnSdsId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NS0ID(HASPROPERTY), sdsId);
    UA_NodeId subscribedDataSetOnSdsId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "SubscribedDataSet"),
                            UA_NS0ID(HASCOMPONENT), sdsId);

    if(UA_NodeId_isNull(&dataSetMetaDataOnSdsId) ||
       UA_NodeId_isNull(&subscribedDataSetOnSdsId))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodeId dataSetMetaDataOnDsrId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NS0ID(HASPROPERTY), dsrId);
    UA_NodeId subscribedDataSetOnDsrId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "SubscribedDataSet"),
                            UA_NS0ID(HASCOMPONENT), dsrId);

    UA_NODESTORE_REMOVE(server, &dataSetMetaDataOnDsrId);
    UA_NODESTORE_REMOVE(server, &subscribedDataSetOnDsrId);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    retVal |= addRef(server, dsrId, UA_NS0ID(HASPROPERTY),
                     dataSetMetaDataOnSdsId, true);
    retVal |= addRef(server, dsrId, UA_NS0ID(HASPROPERTY),
                     subscribedDataSetOnSdsId, true);
    return retVal;
}

/* Remove the references to the SDS */
void
disconnectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_NodeId dataSetMetaDataOnDsrId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NS0ID(HASPROPERTY), dsrId);
    UA_NodeId subscribedDataSetOnDsrId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "SubscribedDataSet"),
                            UA_NS0ID(HASCOMPONENT), dsrId);

    deleteReference(server, dsrId, UA_NS0ID(HASPROPERTY), true,
                    UA_NODEID2EXPANDEDNODEID(dataSetMetaDataOnDsrId), true);

    deleteReference(server, dsrId, UA_NS0ID(HASCOMPONENT), true,
                    UA_NODEID2EXPANDEDNODEID(subscribedDataSetOnDsrId), true);
}

#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */

/**** amalgamated original file "/src/pubsub/ua_pubsub_ns0_sks.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 * Copyright (c) 2025 Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_PUBSUB_SKS

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL

static UA_Boolean
isValidParentNode(UA_Server *server, UA_NodeId parentId) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_Boolean retval = true;
    const UA_Node *parentNodeType;
    const UA_NodeId parentNodeTypeId = UA_NS0ID(SECURITYGROUPFOLDERTYPE);
    const UA_Node *parentNode = UA_NODESTORE_GET(server, &parentId);

    if(parentNode) {
        parentNodeType =
            getNodeType(server, &parentNode->head, ~(UA_UInt32)0,
                        UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
        if(parentNodeType) {
            retval = UA_NodeId_equal(&parentNodeType->head.nodeId, &parentNodeTypeId);
            UA_NODESTORE_RELEASE(server, parentNodeType);
        }
        UA_NODESTORE_RELEASE(server, parentNode);
    }
    return retval;
}

static UA_StatusCode
updateSecurityGroupProperties(UA_Server *server, UA_NodeId *securityGroupNodeId,
                              UA_SecurityGroupConfig *config) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &config->securityGroupName, &UA_TYPES[UA_TYPES_STRING]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "SecurityGroupId"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /*AddCallbackValueSource*/
    UA_Variant_setScalar(&value, &config->securityPolicyUri, &UA_TYPES[UA_TYPES_STRING]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "SecurityPolicyUri"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_Variant_setScalar(&value, &config->keyLifeTime, &UA_TYPES[UA_TYPES_DURATION]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "KeyLifetime"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_Variant_setScalar(&value, &config->maxFutureKeyCount, &UA_TYPES[UA_TYPES_UINT32]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "MaxFutureKeyCount"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_Variant_setScalar(&value, &config->maxPastKeyCount, &UA_TYPES[UA_TYPES_UINT32]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "MaxPastKeyCount"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return retval;
}

UA_StatusCode
addSecurityGroupRepresentation(UA_Server *server, UA_SecurityGroup *securityGroup) {
    UA_LOCK_ASSERT(&server->serviceMutex);
    UA_StatusCode retval = UA_STATUSCODE_BAD;

    UA_SecurityGroupConfig *securityGroupConfig = &securityGroup->config;
    if(!isValidParentNode(server, securityGroup->securityGroupFolderId))
        return UA_STATUSCODE_BADPARENTNODEIDINVALID;

    if(securityGroupConfig->securityGroupName.length <= 0)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_QualifiedName browseName;
    UA_QualifiedName_init(&browseName);
    browseName.name = securityGroupConfig->securityGroupName;

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName.text = securityGroupConfig->securityGroupName;
    UA_NodeId refType = UA_NS0ID(HASCOMPONENT);
    UA_NodeId nodeType = UA_NS0ID(SECURITYGROUPTYPE);
    retval = addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NULL,
                     securityGroup->securityGroupFolderId, refType,
                     browseName, nodeType, &object_attr,
                     &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL,
                     &securityGroup->securityGroupNodeId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Add SecurityGroup failed with error: %s.",
                     UA_StatusCode_name(retval));
        return retval;
    }

    retval = updateSecurityGroupProperties(server,
                                           &securityGroup->securityGroupNodeId,
                                           securityGroupConfig);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Add SecurityGroup failed with error: %s.",
                     UA_StatusCode_name(retval));
        deleteNode(server, securityGroup->securityGroupNodeId, true);
    }
    return retval;
}

/**
 * @note The user credentials and permissions are checked in the AccessControl plugin
 * before this callback is executed.
 */
static UA_StatusCode
setSecurityKeysAction(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Validate the arguments */
    if(!server || !input)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(inputSize < 7)
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    if(inputSize > 7 || outputSize > 0)
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;

    /* Check whether the channel is encrypted according to specification */
    UA_Session *session = getSessionById(server, sessionId);
    if(!session || !session->channel)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(session->channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;

    /* Check for types */
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_STRING]) || /*SecurityGroupId*/
        !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_STRING]) || /*SecurityPolicyUri*/
        !UA_Variant_hasScalarType(&input[2], &UA_TYPES[UA_TYPES_INTEGERID]) || /*CurrentTokenId*/
        !UA_Variant_hasScalarType(&input[3], &UA_TYPES[UA_TYPES_BYTESTRING]) || /*CurrentKey*/
        !UA_Variant_hasArrayType(&input[4], &UA_TYPES[UA_TYPES_BYTESTRING]) || /*FutureKeys*/
        (!UA_Variant_hasScalarType(&input[5], &UA_TYPES[UA_TYPES_DURATION]) &&
        !UA_Variant_hasScalarType(&input[5], &UA_TYPES[UA_TYPES_DOUBLE])) || /*TimeToNextKey*/
        (!UA_Variant_hasScalarType(&input[6], &UA_TYPES[UA_TYPES_DURATION]) &&
        !UA_Variant_hasScalarType(&input[6], &UA_TYPES[UA_TYPES_DOUBLE]))) /*TimeToNextKey*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_Duration callbackTime;
    UA_String *securityGroupId = (UA_String *)input[0].data;
    UA_String *securityPolicyUri = (UA_String *)input[1].data;
    UA_UInt32 currentKeyId = *(UA_UInt32 *)input[2].data;
    UA_ByteString *currentKey = (UA_ByteString *)input[3].data;
    UA_ByteString *futureKeys = (UA_ByteString *)input[4].data;
    size_t futureKeySize = input[4].arrayLength;
    UA_Duration msTimeToNextKey = *(UA_Duration *)input[5].data;
    UA_Duration msKeyLifeTime = *(UA_Duration *)input[6].data;

    UA_PubSubManager *psm = getPSM(server);
    UA_PubSubKeyStorage *ks =
        UA_PubSubKeyStorage_find(psm, *securityGroupId);
    if(!ks)
        return UA_STATUSCODE_BADNOTFOUND;

    if(!UA_String_equal(securityPolicyUri, &ks->policy->policyUri))
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_PubSubKeyListItem *current = UA_PubSubKeyStorage_getKeyByKeyId(ks, currentKeyId);
    if(!current) {
        UA_PubSubKeyStorage_clearKeyList(ks);
        retval |= (UA_PubSubKeyStorage_push(ks, currentKey, currentKeyId)) ?
            UA_STATUSCODE_GOOD : UA_STATUSCODE_BADOUTOFMEMORY;
    }
    UA_PubSubKeyStorage_setCurrentKey(ks, currentKeyId);
    retval |= UA_PubSubKeyStorage_addSecurityKeys(ks, futureKeySize,
                                                  futureKeys, currentKeyId);
    ks->keyLifeTime = msKeyLifeTime;
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_PubSubKeyStorage_activateKeyToChannelContext(psm, UA_NODEID_NULL,
                                                             ks->securityGroupID);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(
            server->config.logging, UA_LOGCATEGORY_SERVER,
            "Failed to import Symmetric Keys into PubSub Channel Context with %s \n",
            UA_StatusCode_name(retval));
        return retval;
    }

    callbackTime = msKeyLifeTime;
    if(msTimeToNextKey > 0)
        callbackTime = msTimeToNextKey;

    /* Move to setSecurityKeysAction */
    return UA_PubSubKeyStorage_addKeyRolloverCallback(
        psm, ks, (UA_Callback)UA_PubSubKeyStorage_keyRolloverCallback,
        callbackTime, &ks->callBackId);
}

static UA_StatusCode
getSecurityKeysAction(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    /* Validate the arguments */
    if(!server || !input)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(inputSize < 3 || outputSize < 5)
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    if(inputSize > 3 || outputSize > 5)
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;

    /* Check whether the channel is encrypted according to specification */
    UA_Session *session = getSessionById(server, sessionId);
    if(!session || !session->channel)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(session->channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;

    /* Check for types */
    if(!UA_Variant_hasScalarType(&input[0],
                                 &UA_TYPES[UA_TYPES_STRING]) || /*SecurityGroupId*/
       !UA_Variant_hasScalarType(&input[1],
                                 &UA_TYPES[UA_TYPES_INTEGERID]) || /*StartingTokenId*/
       !UA_Variant_hasScalarType(&input[2],
                                 &UA_TYPES[UA_TYPES_UINT32])) /*RequestedKeyCount*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_UInt32 currentKeyCount = 1;

    /* Input */
    UA_String *securityGroupId = (UA_String *)input[0].data;
    UA_UInt32 startingTokenId = *(UA_UInt32 *)input[1].data;
    UA_UInt32 requestedKeyCount = *(UA_UInt32 *)input[2].data;

    UA_PubSubManager *psm = getPSM(server);
    UA_PubSubKeyStorage *ks = UA_PubSubKeyStorage_find(psm, *securityGroupId);
    if(!ks)
        return UA_STATUSCODE_BADNOTFOUND;

    UA_Boolean executable = false;
    UA_SecurityGroup *sg = UA_SecurityGroup_findByName(psm, *securityGroupId);
    void *sgNodeCtx;
    getNodeContext(server, sg->securityGroupNodeId, (void **)&sgNodeCtx);
    executable = server->config.accessControl.getUserExecutableOnObject(
        server, &server->config.accessControl, sessionId, sessionContext, methodId,
        methodContext, &sg->securityGroupNodeId, sgNodeCtx);

    if(!executable)
        return UA_STATUSCODE_BADUSERACCESSDENIED;

    /* If the caller requests a number larger than the Security Key Service
     * permits, then the SKS shall return the maximum it allows.*/
    if(requestedKeyCount > sg->config.maxFutureKeyCount)
        requestedKeyCount =(UA_UInt32) sg->keyStorage->keyListSize;
    else
        requestedKeyCount = requestedKeyCount + currentKeyCount; /* Add Current keyCount */

    /* The current token is requested by passing 0. */
    UA_PubSubKeyListItem *startingItem = NULL;
    if(startingTokenId == 0) {
        /* currentItem is always set by the server when a security group is added */
        UA_assert(sg->keyStorage->currentItem != NULL);
        startingItem = sg->keyStorage->currentItem;
    } else {
        startingItem = UA_PubSubKeyStorage_getKeyByKeyId(sg->keyStorage, startingTokenId);
        /* If the StartingTokenId is unknown, the oldest (firstItem) available
         * tokens are returned. */
        if(!startingItem)
            startingItem = TAILQ_FIRST(&sg->keyStorage->keyList);
    }

    /* SecurityPolicyUri */
    retval = UA_Variant_setScalarCopy(&output[0], &(sg->keyStorage->policy->policyUri),
                         &UA_TYPES[UA_TYPES_STRING]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* FirstTokenId */
    retval = UA_Variant_setScalarCopy(&output[1], &startingItem->keyID,
                                      &UA_TYPES[UA_TYPES_INTEGERID]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* TimeToNextKey */
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime baseTime = sg->baseTime;
    UA_DateTime currentTime = el->dateTime_nowMonotonic(el);
    UA_Duration interval = sg->config.keyLifeTime;
    UA_Duration timeToNextKey =
        (UA_Duration)((currentTime - baseTime) / UA_DATETIME_MSEC);
    timeToNextKey = interval - timeToNextKey;
    retval = UA_Variant_setScalarCopy(&output[3], &timeToNextKey,
                                      &UA_TYPES[UA_TYPES_DURATION]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* KeyLifeTime */
    retval = UA_Variant_setScalarCopy(&output[4], &sg->config.keyLifeTime,
                         &UA_TYPES[UA_TYPES_DURATION]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Keys */
    UA_PubSubKeyListItem *iterator = startingItem;
    output[2].data = (UA_ByteString *)
        UA_calloc(requestedKeyCount, startingItem->key.length);
    if(!output[2].data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString *requestedKeys = (UA_ByteString *)output[2].data;
    UA_UInt32 retkeyCount = 0;
    for(size_t i = 0; i < requestedKeyCount; i++) {
        UA_ByteString_copy(&iterator->key, &requestedKeys[i]);
        ++retkeyCount;
        iterator = TAILQ_NEXT(iterator, keyListEntry);
        if(!iterator) {
            requestedKeyCount = retkeyCount;
            break;
        }
    }

    UA_Variant_setArray(&output[2], requestedKeys, requestedKeyCount,
                        &UA_TYPES[UA_TYPES_BYTESTRING]);
    return retval;
}

UA_StatusCode
initPubSubNS0_SKS(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    
    if(server->config.pubSubConfig.enableInformationModelMethods) {
        /* Set SKS method callbacks */
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBLISHSUBSCRIBE_SETSECURITYKEYS), setSecurityKeysAction);
        retVal |= setMethodNode_callback(server, UA_NS0ID(PUBLISHSUBSCRIBE_GETSECURITYKEYS), getSecurityKeysAction);
    }

    return retVal;
}

#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL*/
#endif /* UA_ENABLE_PUBSUB_SKS */

/**** amalgamated original file "/src/pubsub/ua_pubsub_keystorage.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2019 ifak e.V. Magdeburg (Holger Zipper)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB_SKS /* conditional compilation */

#define UA_REQ_CURRENT_TOKEN 0


UA_PubSubKeyStorage *
UA_PubSubKeyStorage_find(UA_PubSubManager *psm, UA_String securityGroupId) {
    if(!psm)
        return NULL;
    UA_PubSubKeyStorage *ks;
    LIST_FOREACH(ks, &psm->pubSubKeyList, keyStorageList) {
        if(UA_String_equal(&ks->securityGroupID, &securityGroupId))
            break;
    }
    return ks;
}

UA_PubSubSecurityPolicy *
findPubSubSecurityPolicy(UA_PubSubManager *psm, const UA_String *securityPolicyUri) {
    if(!psm || !securityPolicyUri)
        return NULL;

    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_ServerConfig *config = &psm->sc.server->config;
    for(size_t i = 0; i < config->pubSubConfig.securityPoliciesSize; i++) {
        if(UA_String_equal(securityPolicyUri,
                           &config->pubSubConfig.securityPolicies[i].policyUri))
            return &config->pubSubConfig.securityPolicies[i];
    }
    return NULL;
}

void
UA_PubSubKeyStorage_clearKeyList(UA_PubSubKeyStorage *ks) {
    if(TAILQ_EMPTY(&ks->keyList))
        return;

    UA_PubSubKeyListItem *item, *item_tmp;
    TAILQ_FOREACH_SAFE(item, &ks->keyList, keyListEntry, item_tmp) {
        TAILQ_REMOVE(&ks->keyList, item, keyListEntry);
        UA_ByteString_clear(&item->key);
        UA_free(item);
    }
    ks->keyListSize = 0;
}

void
UA_PubSubKeyStorage_delete(UA_PubSubManager *psm, UA_PubSubKeyStorage *ks) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Remove callback */
    if(!ks->callBackId) {
        removeCallback(psm->sc.server, ks->callBackId);
        ks->callBackId = 0;
    }

    UA_PubSubKeyStorage_clearKeyList(ks);
    UA_String_clear(&ks->securityGroupID);
    UA_ClientConfig_clear(&ks->sksConfig.clientConfig);
    UA_free(ks);
}

UA_StatusCode
UA_PubSubKeyStorage_init(UA_PubSubManager *psm, UA_PubSubKeyStorage *ks,
                         const UA_String *securityGroupId,
                         UA_PubSubSecurityPolicy *policy,
                         UA_UInt32 maxPastKeyCount, UA_UInt32 maxFutureKeyCount) {
    UA_StatusCode res = UA_String_copy(securityGroupId, &ks->securityGroupID);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_UInt32 currentkeyCount = 1;
    ks->maxPastKeyCount = maxPastKeyCount;
    ks->maxFutureKeyCount = maxFutureKeyCount;
    ks->maxKeyListSize = maxPastKeyCount + currentkeyCount + maxFutureKeyCount;
    ks->policy = policy;

    TAILQ_INIT(&ks->keyList);

    /* Add this keystorage to the keystoragelist */
    LIST_INSERT_HEAD(&psm->pubSubKeyList, ks, keyStorageList);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_PubSubKeyStorage_addSecurityKeys(UA_PubSubKeyStorage *ks, size_t keysSize,
                                    UA_ByteString *keys, UA_UInt32 currentKeyId) {
    for(size_t i = 0; i < keysSize; ++i) {
        currentKeyId++; /* Increase the keyId */
        if(currentKeyId == 0)
            currentKeyId = 1; /* Rollover the keyId */

        /* Search for an existing item matching the tokenId */
        UA_PubSubKeyListItem *item = UA_PubSubKeyStorage_getKeyByKeyId(ks, currentKeyId);

        /* Not found. Add it. */
        if(!item) {
            item = UA_PubSubKeyStorage_push(ks, &keys[i], currentKeyId);
            if(!item)
                return UA_STATUSCODE_BADOUTOFMEMORY;
        }
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_PubSubKeyStorage_setCurrentKey(UA_PubSubKeyStorage *ks, UA_UInt32 keyId) {
    UA_PubSubKeyListItem *item = UA_PubSubKeyStorage_getKeyByKeyId(ks, keyId);
    if(!item)
        return UA_STATUSCODE_BADNOTFOUND;
    ks->currentItem = item;
    return UA_STATUSCODE_GOOD;
}

UA_PubSubKeyListItem *
UA_PubSubKeyStorage_getKeyByKeyId(UA_PubSubKeyStorage *ks,
                                  const UA_UInt32 keyId) {
    UA_PubSubKeyListItem *item;
    TAILQ_FOREACH(item, &ks->keyList, keyListEntry) {
        if(item->keyID == keyId)
            return item;
    }
    return NULL;
}

UA_PubSubKeyListItem *
UA_PubSubKeyStorage_push(UA_PubSubKeyStorage *ks, const UA_ByteString *key,
                         UA_UInt32 keyID) {
    UA_PubSubKeyListItem *newItem = (UA_PubSubKeyListItem *)
        UA_malloc(sizeof(UA_PubSubKeyListItem));
    if(!newItem)
        return NULL;
    newItem->keyID = keyID;
    UA_StatusCode res = UA_ByteString_copy(key, &newItem->key);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(newItem);
        return NULL;
    }
    TAILQ_INSERT_TAIL(&ks->keyList, newItem, keyListEntry);
    ks->keyListSize++;
    return newItem;
}

UA_StatusCode
UA_PubSubKeyStorage_addKeyRolloverCallback(UA_PubSubManager *psm,
                                           UA_PubSubKeyStorage *ks,
                                           UA_Callback callback,
                                           UA_Duration timeToNextMs,
                                           UA_UInt64 *callbackID) {
    if(!psm || !ks || !callback || timeToNextMs <= 0)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_EventLoop *el = psm->sc.server->config.eventLoop;

    if(*callbackID != 0)
        el->removeTimer(el, *callbackID);

    return el->addTimer(el, (UA_Callback)callback, psm, ks,
                        timeToNextMs, NULL, UA_TIMERPOLICY_ONCE, callbackID);

}

static UA_StatusCode
splitCurrentKeyMaterial(UA_PubSubKeyStorage *ks, UA_ByteString *signingKey,
                        UA_ByteString *encryptingKey, UA_ByteString *keyNonce) {
    if(!ks)
        return UA_STATUSCODE_BADNOTFOUND;
    if(!ks->policy)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_PubSubSecurityPolicy *policy = ks->policy;
    UA_ByteString key = ks->currentItem->key;

    /* Check the main key length is the same according to policy */
    if(key.length != policy->nonceLength)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Get key length according to policy */
    size_t signingkeyLength = policy->getSignatureKeyLength(policy, NULL);
    size_t encryptkeyLength = policy->getEncryptionKeyLength(policy, NULL);

    /* Rest of the part is the keyNonce */
    size_t keyNonceLength = key.length - signingkeyLength - encryptkeyLength;

    /* DivideKeys in origin ByteString */
    signingKey->data = key.data;
    signingKey->length = signingkeyLength;
    encryptingKey->data = key.data + signingkeyLength;
    encryptingKey->length = encryptkeyLength;
    keyNonce->data = key.data + signingkeyLength + encryptkeyLength;
    keyNonce->length = keyNonceLength;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setPubSubGroupEncryptingKey(UA_PubSubManager *psm, UA_NodeId PubSubGroupId,
                            UA_UInt32 securityTokenId, UA_ByteString signingKey,
                            UA_ByteString encryptingKey, UA_ByteString keyNonce) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);
    UA_WriterGroup *wg = UA_WriterGroup_find(psm, PubSubGroupId);
    if(wg)
        return UA_WriterGroup_setEncryptionKeys(psm, wg, securityTokenId, signingKey,
                                                encryptingKey, keyNonce);

    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, PubSubGroupId);
    if(rg)
        return UA_ReaderGroup_setEncryptionKeys(psm, rg, securityTokenId, signingKey,
                                                encryptingKey, keyNonce);

    return UA_STATUSCODE_BADNOTFOUND;
}

static UA_StatusCode
setPubSubGroupEncryptingKeyForMatchingSecurityGroupId(UA_PubSubManager *psm,
                                                      UA_String securityGroupId,
                                                      UA_UInt32 securityTokenId,
                                                      UA_ByteString signingKey,
                                                      UA_ByteString encryptingKey,
                                                      UA_ByteString keyNonce) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Key storage is the same for all reader / writer groups, channel context isn't
     * => Update channelcontext in all Writergroups / ReaderGroups which have the same
     * securityGroupId*/
    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_PubSubConnection *c;
    TAILQ_FOREACH(c, &psm->connections, listEntry) {
        /* For each writerGroup in server with matching SecurityGroupId */
        UA_WriterGroup *wg;
        LIST_FOREACH(wg, &c->writerGroups, listEntry) {
            if(UA_String_equal(&wg->config.securityGroupId, &securityGroupId)) {
                retval = UA_WriterGroup_setEncryptionKeys(psm, wg, securityTokenId,
                                                          signingKey, encryptingKey, keyNonce);
                if(retval != UA_STATUSCODE_GOOD)
                    return retval;
            }
        }

        /* For each readerGroup in server with matching SecurityGroupId */
        UA_ReaderGroup *rg;
        LIST_FOREACH(rg, &c->readerGroups, listEntry) {
            if(UA_String_equal(&rg->config.securityGroupId, &securityGroupId)) {
                retval = UA_ReaderGroup_setEncryptionKeys(psm, rg, securityTokenId,
                                                          signingKey, encryptingKey, keyNonce);
                if(retval != UA_STATUSCODE_GOOD)
                    return retval;
            }
        }
    }
    return retval;
}

UA_StatusCode
UA_PubSubKeyStorage_activateKeyToChannelContext(UA_PubSubManager *psm,
                                                UA_NodeId pubSubGroupId,
                                                UA_String securityGroupId) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);
    if(securityGroupId.data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_PubSubKeyStorage *ks =
        UA_PubSubKeyStorage_find(psm, securityGroupId);
    if(!ks)
        return UA_STATUSCODE_BADNOTFOUND;

    if(!ks->policy && !(ks->keyListSize > 0))
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_UInt32 securityTokenId = ks->currentItem->keyID;

    /*DivideKeys in origin ByteString*/
    UA_ByteString signingKey;
    UA_ByteString encryptKey;
    UA_ByteString keyNonce;
    UA_StatusCode retval = splitCurrentKeyMaterial(ks, &signingKey,
                                                   &encryptKey, &keyNonce);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(!UA_NodeId_isNull(&pubSubGroupId))
        retval = setPubSubGroupEncryptingKey(psm, pubSubGroupId, securityTokenId,
                                             signingKey, encryptKey, keyNonce);
    else
        retval = setPubSubGroupEncryptingKeyForMatchingSecurityGroupId(
            psm, securityGroupId, securityTokenId, signingKey, encryptKey, keyNonce);

    if(retval != UA_STATUSCODE_GOOD)
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "Failed to set Encrypting keys with Error: %s",
                     UA_StatusCode_name(retval));

    return retval;
}

static void
nextGetSecuritykeysCallback(UA_PubSubManager *psm, UA_PubSubKeyStorage *ks) {
    UA_StatusCode retval = UA_STATUSCODE_BAD;
    if(!ks) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_SERVER,
                     "GetSecurityKeysCall Failed with error: KeyStorage does not exist "
                     "in the server");
        return;
    }
    retval = getSecurityKeysAndStoreFetchedKeys(psm, ks);
    if(retval != UA_STATUSCODE_GOOD)
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_SERVER,
                     "GetSecurityKeysCall Failed with error: %s ",
                     UA_StatusCode_name(retval));
}

void
UA_PubSubKeyStorage_keyRolloverCallback(UA_PubSubManager *psm, UA_PubSubKeyStorage *ks) {
    /* Callbacks from the EventLoop are initially unlocked */
    lockServer(psm->sc.server);

    UA_StatusCode retval =
        UA_PubSubKeyStorage_addKeyRolloverCallback(psm, ks,
                                                   (UA_Callback)UA_PubSubKeyStorage_keyRolloverCallback,
                                                   ks->keyLifeTime, &ks->callBackId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_SERVER,
                     "Failed to update keys for security group id '%S'. Reason: '%s'.",
                     ks->securityGroupID, UA_StatusCode_name(retval));
    }

    if(ks->currentItem != TAILQ_LAST(&ks->keyList, keyListItems)) {
        ks->currentItem = TAILQ_NEXT(ks->currentItem, keyListEntry);
        ks->currentTokenId = ks->currentItem->keyID;
        retval = UA_PubSubKeyStorage_activateKeyToChannelContext(psm, UA_NODEID_NULL,
                                                                 ks->securityGroupID);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_SERVER,
                         "Failed to update keys for security group id '%S'. Reason: '%s'.",
                         ks->securityGroupID, UA_StatusCode_name(retval));
        }
    } else if(ks->sksConfig.endpointUrl && ks->sksConfig.reqId == 0) {
        /* Publishers using a central SKS shall call GetSecurityKeys at a period
         * of half the KeyLifetime */
        UA_Duration msTimeToNextGetSecurityKeys = ks->keyLifeTime / 2;
        UA_EventLoop *el = psm->sc.server->config.eventLoop;
        retval = el->addTimer(el, (UA_Callback)nextGetSecuritykeysCallback, psm,
                              ks, msTimeToNextGetSecurityKeys, NULL,
                              UA_TIMERPOLICY_ONCE, NULL);
    }

    unlockServer(psm->sc.server);
}

void
UA_PubSubKeyStorage_detachKeyStorage(UA_PubSubManager *psm, UA_PubSubKeyStorage *ks) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);
    ks->referenceCount--;
    if(ks->referenceCount == 0) {
        LIST_REMOVE(ks, keyStorageList);
        UA_PubSubKeyStorage_delete(psm, ks);
    }
}

/**
 * @brief It holds the information required in the async callback to
 * GetSecurityKeys method Call.
 */
typedef struct {
    UA_PubSubManager *psm;
    UA_PubSubKeyStorage *ks;
    UA_UInt32 startingTokenId;
    UA_UInt32 requestedKeyCount;
    UA_DelayedCallback dc;
} sksClientContext;

static void sksClientCleanupCb(void *client, void *context);

static void
addDelayedSksClientCleanupCb(UA_Client *client, sksClientContext *context) {
    /* Register at most once */
    if(context->dc.application != NULL)
        return;
    context->dc.application = client;
    context->dc.callback = sksClientCleanupCb;
    context->dc.context = context;
    client->config.eventLoop->addDelayedCallback(client->config.eventLoop, &context->dc);
}

static void
sksClientCleanupCb(void *client, void *context) {
    UA_Client *sksClient = (UA_Client *)client;
    sksClientContext *ctx = (sksClientContext*)context;

    /* we do not want to call state change Callback when cleaning up */
    sksClient->config.stateCallback = NULL;

    if(sksClient->sessionState > UA_SESSIONSTATE_CLOSED &&
       sksClient->channel.state < UA_SECURECHANNELSTATE_CLOSED) {
        sksClient->config.eventLoop->
            addDelayedCallback(sksClient->config.eventLoop, &ctx->dc);
        UA_Client_disconnectAsync(sksClient);
        return;
    }

    if(sksClient->channel.state == UA_SECURECHANNELSTATE_CLOSED) {
        /* We cannot make deep copy of the following pointers because these have
         * internal structures, therefore we do not free them here. These will
         * be freed in UA_PubSubKeyStorage_delete. */
        sksClient->config.securityPolicies = NULL;
        sksClient->config.securityPoliciesSize = 0;
        sksClient->config.authSecurityPolicies = NULL;
        sksClient->config.authSecurityPoliciesSize = 0;
        sksClient->config.certificateVerification.context = NULL;
        sksClient->config.logging = NULL;
        sksClient->config.clientContext = NULL;
        UA_Client_delete(sksClient);
        UA_free(context);
    } else {
        sksClient->config.eventLoop->
            addDelayedCallback(sksClient->config.eventLoop, &ctx->dc);
    }
}

static void
storeFetchedKeys(UA_Client *client, void *userdata, UA_UInt32 requestId,
                 UA_CallResponse *response) {
    sksClientContext *ctx = (sksClientContext *)userdata;
    UA_PubSubKeyStorage *ks = ctx->ks;
    UA_PubSubManager *psm = ctx->psm;
    UA_StatusCode retval = response->responseHeader.serviceResult;

    lockServer(psm->sc.server);
    /* check if the call to getSecurityKeys was a success */
    if(response->resultsSize != 0)
        retval = response->results->statusCode;
    if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_SERVER,
                     "SKS Client: Failed to call GetSecurityKeys on SKS server with error: %s ",
                     UA_StatusCode_name(retval));
        goto cleanup;
    }

    UA_String *securityPolicyUri = (UA_String *)response->results->outputArguments[0].data;
    UA_UInt32 firstTokenId = *(UA_UInt32 *)response->results->outputArguments[1].data;
    UA_ByteString *keys = (UA_ByteString *)response->results->outputArguments[2].data;
    UA_ByteString *currentKey = &keys[0];
    UA_UInt32 currentKeyCount = 1;
    UA_ByteString *futureKeys = &keys[currentKeyCount];
    size_t futureKeySize = response->results->outputArguments[2].arrayLength - currentKeyCount;
    UA_Duration msKeyLifeTime = *(UA_Duration *)response->results->outputArguments[4].data;

    if(!UA_String_equal(securityPolicyUri, &ks->policy->policyUri)) {
        retval = UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
        goto cleanup;
    }

    UA_PubSubKeyListItem *current = UA_PubSubKeyStorage_getKeyByKeyId(ks, firstTokenId);
    if(!current) {
        UA_PubSubKeyStorage_clearKeyList(ks);
        retval |= (UA_PubSubKeyStorage_push(ks, currentKey, firstTokenId)) ?
            UA_STATUSCODE_GOOD : UA_STATUSCODE_BADOUTOFMEMORY;
    }
    UA_PubSubKeyStorage_setCurrentKey(ks, firstTokenId);
    retval |= UA_PubSubKeyStorage_addSecurityKeys(ks, futureKeySize, futureKeys, firstTokenId);
    ks->keyLifeTime = msKeyLifeTime;
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* After a new batch of keys is fetched from SKS server, the key storage is
     * updated with new keys and new keylifetime. Also the remaining time for
     * current keyRollover is also returned. When setting a new keyRollover
     * callback, the previous callback must be removed so that the keyRollover
     * does not happen twice */
    if(ks->callBackId != 0) {
        psm->sc.server->config.eventLoop->removeTimer(psm->sc.server->config.eventLoop,
                                                      ks->callBackId);
        ks->callBackId = 0;
    }

    UA_Duration msTimeToNextKey =
        *(UA_Duration *)response->results->outputArguments[3].data;
    if(!(msTimeToNextKey > 0))
        msTimeToNextKey = ks->keyLifeTime;
    retval = UA_PubSubKeyStorage_addKeyRolloverCallback(
        psm, ks, (UA_Callback)UA_PubSubKeyStorage_keyRolloverCallback,
        msTimeToNextKey, &ks->callBackId);

cleanup:
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "Failed to store the fetched keys from SKS server with error: %s",
                     UA_StatusCode_name(retval));
    }

    /* Call user callback to notify about the status */
    if(ks->sksConfig.userNotifyCallback)
        ks->sksConfig.userNotifyCallback(psm->sc.server, retval, ks->sksConfig.context);
    ks->sksConfig.reqId = 0;
    UA_Client_disconnectAsync(client);
    addDelayedSksClientCleanupCb(client, ctx);

    unlockServer(psm->sc.server);
}

static UA_StatusCode
callGetSecurityKeysMethod(UA_Client *client) {

    sksClientContext *ctx = (sksClientContext *)client->config.clientContext;

    UA_Variant inputArguments[3];
    UA_Variant_setScalar(&inputArguments[0], &ctx->ks->securityGroupID,
                         &UA_TYPES[UA_TYPES_STRING]);
    UA_Variant_setScalar(&inputArguments[1], &ctx->startingTokenId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&inputArguments[2], &ctx->requestedKeyCount,
                         &UA_TYPES[UA_TYPES_UINT32]);

    UA_NodeId objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE);
    UA_NodeId methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_GETSECURITYKEYS);
    size_t inputArgumentsSize = 3;

    UA_StatusCode retval = UA_Client_call_async(
        client, objectId, methodId, inputArgumentsSize, inputArguments, storeFetchedKeys,
        (void *)ctx, &ctx->ks->sksConfig.reqId);
    return retval;
}

static void
onConnect(UA_Client *client, UA_SecureChannelState channelState,
          UA_SessionState sessionState, UA_StatusCode connectStatus) {
    UA_Boolean triggerSKSCleanup = false;
    if(connectStatus != UA_STATUSCODE_GOOD &&
       connectStatus != UA_STATUSCODE_BADNOTCONNECTED &&
       sessionState != UA_SESSIONSTATE_ACTIVATED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "SKS Client: Failed to connect SKS server with error: %s ",
                     UA_StatusCode_name(connectStatus));
        triggerSKSCleanup = true;
    }
    if(connectStatus == UA_STATUSCODE_GOOD && sessionState == UA_SESSIONSTATE_ACTIVATED) {
        connectStatus = callGetSecurityKeysMethod(client);
        if(connectStatus != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_SERVER,
                         "SKS Client: Failed to call GetSecurityKeys on SKS server with "
                         "error: %s ",
                         UA_StatusCode_name(connectStatus));
            triggerSKSCleanup = true;
        }
    }
    if(triggerSKSCleanup) {
        /* call user callback to notify about the status */
        sksClientContext *ctx = (sksClientContext *)client->config.clientContext;
        UA_PubSubKeyStorage *ks = ctx->ks;
        if(ks->sksConfig.userNotifyCallback)
            ks->sksConfig.userNotifyCallback(ctx->psm->sc.server, connectStatus,
                                             ks->sksConfig.context);
        UA_Client_disconnectAsync(client);
        addDelayedSksClientCleanupCb(client, ctx);
    }
}

static void
setServerEventloopOnSksClient(UA_ClientConfig *cc, UA_EventLoop *externalEventloop) {
    UA_assert(externalEventloop != NULL);
    cc->eventLoop = externalEventloop;
    cc->externalEventLoop = true;
}

UA_StatusCode
getSecurityKeysAndStoreFetchedKeys(UA_PubSubManager *psm, UA_PubSubKeyStorage *ks) {
    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_UInt32 startingTokenId = UA_REQ_CURRENT_TOKEN;
    UA_UInt32 requestKeyCount = UA_UINT32_MAX;

    if(ks->sksConfig.reqId != 0) {
        UA_LOG_INFO(psm->logging, UA_LOGCATEGORY_PUBSUB,
                    "SKS Client: SKS Pull request in process ");
        return UA_STATUSCODE_GOOD;
    }

    UA_ClientConfig cc;
    memset(&cc, 0, sizeof(UA_ClientConfig));

    /* over write the client config with user specified SKS config */
    retval = UA_ClientConfig_copy(&ks->sksConfig.clientConfig, &cc);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    setServerEventloopOnSksClient(&cc, psm->sc.server->config.eventLoop);

    /* this is cleanedup in sksClientCleanupCb */
    sksClientContext *ctx   = (sksClientContext *)UA_calloc(1, sizeof(sksClientContext));
    if(!ctx)
         return UA_STATUSCODE_BADOUTOFMEMORY;
    ctx->ks = ks;
    ctx->psm = psm;
    ctx->startingTokenId = startingTokenId;
    ctx->requestedKeyCount = requestKeyCount;
    cc.clientContext = ctx;

    UA_Client *client = UA_Client_newWithConfig(&cc);
    if(!client)
        return retval;
    /* connect to sks server */
    retval = UA_Client_connectAsync(client, ks->sksConfig.endpointUrl);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Failed to connect SKS server with error: %s ",
                     UA_StatusCode_name(retval));
        /* Make sure the client channel state is closed and not fresh,
         * otherwise, eventloop will keep waiting for the client status to go
         * from Fresh to closed in UA_Client_delete*/
        client->channel.state = UA_SECURECHANNELSTATE_CLOSED;
        /* this client instance will be cleared in the next event loop
         * iteration */
        addDelayedSksClientCleanupCb(client, ctx);
        return retval;
    }

    /* add user specified callback, if the client is properly configured. */
    client->config.stateCallback = onConnect;

    return retval;
}

UA_StatusCode
UA_Server_setSksClient(UA_Server *server, UA_String securityGroupId,
                       UA_ClientConfig *clientConfig, const char *endpointUrl,
                       UA_Server_sksPullRequestCallback callback, void *context) {
    if(!server || !clientConfig || !endpointUrl)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode retval = UA_STATUSCODE_BADNOTFOUND;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_PubSubKeyStorage *ks = UA_PubSubKeyStorage_find(psm, securityGroupId);
    if(!ks) {
        unlockServer(server);
        return retval;
    }

    UA_ClientConfig_copy(clientConfig, &ks->sksConfig.clientConfig);
    /*Clear the content of original config, so that no body can access the original config */
    clientConfig->authSecurityPolicies = NULL;
    clientConfig->certificateVerification.context = NULL;
    clientConfig->eventLoop = NULL;
    clientConfig->logging = NULL;
    clientConfig->securityPolicies = NULL;
    UA_ClientConfig_clear(clientConfig);

    ks->sksConfig.endpointUrl = endpointUrl;
    ks->sksConfig.userNotifyCallback = callback;
    ks->sksConfig.context = context;
    /* if keys are not previously fetched, then first call GetSecurityKeys*/
    if(ks->keyListSize == 0) {
        retval = getSecurityKeysAndStoreFetchedKeys(psm, ks);
    }
    unlockServer(server);
    return retval;
}

#endif

/**** amalgamated original file "/src/pubsub/ua_pubsub_securitygroup.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2019 ifak e.V. Magdeburg (Holger Zipper)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 * Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_PUBSUB_SKS /* conditional compilation */


#define UA_PUBSUB_KEYMATERIAL_NONCELENGTH 32

static void
UA_SecurityGroup_delete(UA_SecurityGroup *sg) {
    UA_String_clear(&sg->config.securityGroupName);
    UA_String_clear(&sg->config.securityPolicyUri);
    UA_String_clear(&sg->securityGroupId);
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    UA_NodeId_clear(&sg->securityGroupFolderId);
#endif
    UA_NodeId_clear(&sg->securityGroupNodeId);
    UA_free(sg);
}

UA_SecurityGroup *
UA_SecurityGroup_findByName(UA_PubSubManager *psm, const UA_String name) {
    if(!psm)
        return NULL;
    UA_SecurityGroup *sg;
    TAILQ_FOREACH(sg, &psm->securityGroups, listEntry) {
        if(UA_String_equal(&name, &sg->config.securityGroupName))
            break;
    }
    return sg;
}

UA_SecurityGroup *
UA_SecurityGroup_find(UA_PubSubManager *psm, const UA_NodeId id) {
    if(!psm)
        return NULL;
    UA_SecurityGroup *sg;
    TAILQ_FOREACH(sg, &psm->securityGroups, listEntry) {
        if(UA_NodeId_equal(&id, &sg->securityGroupNodeId))
            break;
    }
    return sg;
}

UA_StatusCode
UA_SecurityGroupConfig_copy(const UA_SecurityGroupConfig *src,
                            UA_SecurityGroupConfig *dst) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    memcpy(dst, src, sizeof(UA_SecurityGroupConfig));
    if(UA_String_copy(&src->securityGroupName, &dst->securityGroupName) !=
       UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BAD;

    if(UA_String_copy(&src->securityPolicyUri, &dst->securityPolicyUri) !=
       UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BAD;
    return retval;
}

static UA_StatusCode
generateKeyData(UA_PubSubSecurityPolicy *policy, UA_ByteString *key) {
    if(!key || !policy)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode retVal;

    /* Can't not found in specification for pubsub key generation, so use the
     * idea of securechannel, see specification 1.0.3 6.7.5 Deriving keys for
     * more details In pubsub we do get have OpenSecureChannel request, so we
     * cannot have Client or Server Nonce*/
    UA_Byte secretBytes[UA_PUBSUB_KEYMATERIAL_NONCELENGTH];
    UA_ByteString secret;
    secret.length = UA_PUBSUB_KEYMATERIAL_NONCELENGTH;
    secret.data = secretBytes;

    UA_Byte seedBytes[UA_PUBSUB_KEYMATERIAL_NONCELENGTH];
    UA_ByteString seed;
    seed.data = seedBytes;
    seed.length = UA_PUBSUB_KEYMATERIAL_NONCELENGTH;
    memset(seed.data, 0, seed.length);
    retVal = policy->generateNonce(policy, NULL, &secret);
    retVal |= policy->generateNonce(policy, NULL, &seed);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    retVal = policy->generateKey(policy, NULL, &secret, &seed, key);
    return retVal;
}

static void
updateSKSKeyStorage(UA_PubSubManager *psm, UA_SecurityGroup *sg) {
    if(!sg) {
        UA_LOG_WARNING(psm->logging, UA_LOGCATEGORY_PUBSUB,
                       "UpdateSKSKeyStorage callback failed with Error: %s ",
                       UA_StatusCode_name(UA_STATUSCODE_BADINVALIDARGUMENT));
        return;
    }

    UA_PubSubKeyStorage *keyStorage = sg->keyStorage;

    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_ByteString newKey;
    size_t keyLength = keyStorage->policy->nonceLength;

    retval = UA_ByteString_allocBuffer(&newKey, keyLength);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(psm->logging, UA_LOGCATEGORY_PUBSUB,
                       "UpdateSKSKeyStorage callback failed to allocate memory for new key with Error: %s ",
                       UA_StatusCode_name(retval));
        return;
    }

    generateKeyData(keyStorage->policy, &newKey);
    UA_UInt32 newKeyID = TAILQ_LAST(&keyStorage->keyList, keyListItems)->keyID;

    if(newKeyID >= UA_UINT32_MAX)
        newKeyID = 1;
    else
        ++newKeyID;

    if(keyStorage->keyListSize >= keyStorage->maxKeyListSize) {
        /* reusing the preallocated memory of the oldest key for the new key material */
        UA_PubSubKeyListItem *oldestKey = TAILQ_FIRST(&keyStorage->keyList);
        TAILQ_REMOVE(&keyStorage->keyList, oldestKey, keyListEntry);
        TAILQ_INSERT_TAIL(&keyStorage->keyList, oldestKey, keyListEntry);
        UA_ByteString_clear(&oldestKey->key);
        oldestKey->keyID = newKeyID;
        UA_ByteString_copy(&newKey, &oldestKey->key);
    } else {
        UA_PubSubKeyListItem *newItem =
            UA_PubSubKeyStorage_push(keyStorage, &newKey, newKeyID);
        if(!newItem) {
            UA_LOG_WARNING(psm->logging, UA_LOGCATEGORY_PUBSUB,
                           "UpdateSKSKeyStorage callback failed to add new key to the "
                           "sks keystorage for the SecurityGroup %S",
                           sg->securityGroupId);
            UA_Byte_delete(newKey.data);
            return;
        }
    }

    UA_PubSubKeyListItem *nextCurrentItem = TAILQ_NEXT(keyStorage->currentItem, keyListEntry);
    if(nextCurrentItem)
        keyStorage->currentItem = nextCurrentItem;

    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    el->modifyTimer(el, sg->callbackId, sg->config.keyLifeTime,
                    NULL, UA_TIMERPOLICY_CURRENTTIME);

    /* We allocated memory for data with allocBuffer so now we free it */
    UA_ByteString_clear(&newKey);
}

static UA_StatusCode
initializeKeyStorageWithKeys(UA_PubSubManager *psm, UA_SecurityGroup *sg) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PubSubSecurityPolicy *policy =
        findPubSubSecurityPolicy(psm, &sg->config.securityPolicyUri);
    if(!policy)
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    UA_PubSubKeyStorage *ks = (UA_PubSubKeyStorage *)
        UA_calloc(1, sizeof(UA_PubSubKeyStorage));
    if(!ks)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_PubSubKeyStorage_init(psm, ks, &sg->securityGroupId,
                                 policy, sg->config.maxPastKeyCount,
                                 sg->config.maxFutureKeyCount);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(ks);
        return retval;
    }

    ks->referenceCount++;
    sg->keyStorage = ks;

    UA_ByteString currentKey;
    size_t keyLength = ks->policy->nonceLength;
    retval = UA_ByteString_allocBuffer(&currentKey, keyLength);
    retval = generateKeyData(ks->policy, &currentKey);

    UA_ByteString *futurekeys = (UA_ByteString *)
        UA_calloc(sg->config.maxFutureKeyCount, sizeof(UA_ByteString));
    for(size_t i = 0; i < sg->config.maxFutureKeyCount; i++) {
        retval = UA_ByteString_allocBuffer(&futurekeys[i], keyLength);
        retval = generateKeyData(ks->policy, &futurekeys[i]);
    }

    UA_UInt32 startingKeyId = 1;
    retval |= (UA_PubSubKeyStorage_push(ks, &currentKey, startingKeyId)) ?
        UA_STATUSCODE_GOOD : UA_STATUSCODE_BADOUTOFMEMORY;
    UA_PubSubKeyStorage_setCurrentKey(ks, startingKeyId);
    retval |= UA_PubSubKeyStorage_addSecurityKeys(ks, sg->config.maxFutureKeyCount,
                                                  futurekeys, startingKeyId);
    ks->keyLifeTime = sg->config.keyLifeTime;
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    UA_EventLoop *el = psm->sc.server->config.eventLoop;
    retval = el->addTimer(el, (UA_Callback)updateSKSKeyStorage, psm,
                          sg, sg->config.keyLifeTime, NULL,
                          UA_TIMERPOLICY_CURRENTTIME, &sg->callbackId);

cleanup:
    UA_Array_delete(futurekeys, sg->config.maxFutureKeyCount,
                    &UA_TYPES[UA_TYPES_BYTESTRING]);
    UA_ByteString_clear(&currentKey);
    if(retval != UA_STATUSCODE_GOOD)
        UA_PubSubKeyStorage_delete(psm, ks);
    return retval;
}

static UA_StatusCode
addSecurityGroup(UA_PubSubManager *psm, UA_NodeId securityGroupFolderNodeId,
                 const UA_SecurityGroupConfig *securityGroupConfig,
                 UA_NodeId *securityGroupNodeId) {
    if(!securityGroupConfig || !psm)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /*check minimal config parameters*/
    if(!securityGroupConfig->keyLifeTime ||
       UA_String_isEmpty(&securityGroupConfig->securityGroupName) ||
       UA_String_isEmpty(&securityGroupConfig->securityPolicyUri))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    if(UA_SecurityGroup_findByName(psm, securityGroupConfig->securityGroupName))
        return UA_STATUSCODE_BADNODEIDEXISTS;

    UA_PubSubSecurityPolicy *policy =
        findPubSubSecurityPolicy(psm, &securityGroupConfig->securityPolicyUri);
    if(!policy)
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    if(securityGroupConfig->securityGroupName.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval = UA_STATUSCODE_BAD;

    UA_SecurityGroup *newSecurityGroup =
        (UA_SecurityGroup *)UA_calloc(1, sizeof(UA_SecurityGroup));
    if(!newSecurityGroup)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    memset(newSecurityGroup, 0, sizeof(UA_SecurityGroup));
    UA_SecurityGroupConfig_copy(securityGroupConfig, &newSecurityGroup->config);

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    retval = UA_NodeId_copy(&securityGroupFolderNodeId,
                            &newSecurityGroup->securityGroupFolderId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }
#endif

    retval = UA_String_copy(&securityGroupConfig->securityGroupName,
                            &newSecurityGroup->securityGroupId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }

    retval = initializeKeyStorageWithKeys(psm, newSecurityGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    retval = addSecurityGroupRepresentation(psm->sc.server, newSecurityGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_SERVER,
                     "Add SecurityGroup failed with error: %s.",
                     UA_StatusCode_name(retval));
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(psm, &newSecurityGroup->securityGroupNodeId);
#endif
    if(securityGroupNodeId)
        UA_NodeId_copy(&newSecurityGroup->securityGroupNodeId, securityGroupNodeId);

    TAILQ_INSERT_TAIL(&psm->securityGroups, newSecurityGroup, listEntry);

    psm->securityGroupsSize++;
    return retval;
}

UA_StatusCode
UA_Server_addSecurityGroup(UA_Server *server, UA_NodeId securityGroupFolderNodeId,
                           const UA_SecurityGroupConfig *securityGroupConfig,
                           UA_NodeId *securityGroupNodeId) {
    if(!server || !securityGroupConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_StatusCode retval = addSecurityGroup(psm, securityGroupFolderNodeId,
                                            securityGroupConfig, securityGroupNodeId);
    unlockServer(server);
    return retval;
}

void
UA_SecurityGroup_remove(UA_PubSubManager *psm, UA_SecurityGroup *sg) {
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(psm->sc.server, sg->securityGroupNodeId, true);
#endif

    /* Unlink from the server */
    TAILQ_REMOVE(&psm->securityGroups, sg, listEntry);
    psm->securityGroupsSize--;
    if(sg->callbackId > 0)
        removeCallback(psm->sc.server, sg->callbackId);

    if(sg->keyStorage) {
        UA_PubSubKeyStorage_detachKeyStorage(psm, sg->keyStorage);
        sg->keyStorage = NULL;
    }

    UA_SecurityGroup_delete(sg);
}

UA_StatusCode
UA_Server_removeSecurityGroup(UA_Server *server, const UA_NodeId securityGroup) {
    if(!server)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    lockServer(server);
    UA_PubSubManager *psm = getPSM(server);
    UA_SecurityGroup *sg = UA_SecurityGroup_find(psm, securityGroup);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(sg)
        UA_SecurityGroup_remove(psm, sg);
    else
        res = UA_STATUSCODE_BADBOUNDNOTFOUND;
    unlockServer(server);
    return res;
}

#endif

/**** amalgamated original file "/src/pubsub/ua_pubsub_config.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 * Copyright (c) 2025 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2025 Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#if defined(UA_ENABLE_PUBSUB) && defined(UA_ENABLE_PUBSUB_FILE_CONFIG)


static UA_StatusCode
createPubSubConnection(UA_PubSubManager *psm,
                       const UA_PubSubConnectionDataType *connection,
                       UA_UInt32 pdsCount, UA_NodeId *pdsIdent, UA_NodeId *connectionIdent);

static UA_StatusCode
createWriterGroup(UA_PubSubManager *psm,
                  const UA_WriterGroupDataType *writerGroupParameters,
                  UA_NodeId connectionIdent, UA_UInt32 pdsCount,
                  const UA_NodeId *pdsIdent);

static UA_StatusCode
createDataSetWriter(UA_PubSubManager *psm,
                    const UA_DataSetWriterDataType *dataSetWriterParameters,
                    UA_NodeId writerGroupIdent, UA_UInt32 pdsCount,
                    const UA_NodeId *pdsIdent);

static UA_StatusCode
createReaderGroup(UA_PubSubManager *psm,
                  const UA_ReaderGroupDataType *readerGroupParameters,
                  UA_NodeId connectionIdent);

static UA_StatusCode
createDataSetReader(UA_PubSubManager *psm,
                    const UA_DataSetReaderDataType *dataSetReaderParameters,
                    UA_NodeId readerGroupIdent);

static UA_StatusCode
createPublishedDataSet(UA_PubSubManager *psm,
                       const UA_PublishedDataSetDataType *publishedDataSetParameters,
                       UA_NodeId *publishedDataSetIdent);

static UA_StatusCode
createDataSetFields(UA_PubSubManager *psm,
                    const UA_NodeId *publishedDataSetIdent,
                    const UA_PublishedDataSetDataType *publishedDataSetParameters);

static UA_StatusCode
generatePubSubConfigurationDataType(UA_PubSubManager *psm,
                                    UA_PubSubConfigurationDataType *pubSubConfiguration);

/* Gets PubSub Configuration from an ExtensionObject */
static UA_StatusCode
extractPubSubConfigFromExtensionObject(UA_PubSubManager *psm,
                                       const UA_ExtensionObject *src,
                                       UA_PubSubConfigurationDataType **dst) {
    if(src->encoding != UA_EXTENSIONOBJECT_DECODED ||
       src->content.decoded.type != &UA_TYPES[UA_TYPES_UABINARYFILEDATATYPE]) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] "
                     "Reading extensionObject failed");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_UABinaryFileDataType *binFile = (UA_UABinaryFileDataType*)src->content.decoded.data;

    if(binFile->body.arrayLength != 0 || binFile->body.arrayDimensionsSize != 0) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] "
                     "Loading multiple configurations is not supported");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    if(binFile->body.type != &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONDATATYPE]) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] "
                     "Invalid datatype encoded in the binary file");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    *dst = (UA_PubSubConfigurationDataType*)binFile->body.data;
    return UA_STATUSCODE_GOOD;
}

/* Configures with given PubSubConfigurationDataType object */
static UA_StatusCode
updatePubSubConfig(UA_PubSubManager *psm,
                   const UA_PubSubConfigurationDataType *configurationParameters) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    if(configurationParameters == NULL) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_updatePubSubConfig] Invalid argument");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Check if the PubSubManager is in an active state and has connections attached. */
    if(psm->sc.state != UA_LIFECYCLESTATE_STOPPED && psm->connectionsSize > 0) {
        UA_LOG_WARNING(psm->logging, UA_LOGCATEGORY_PUBSUB,
                       "[UA_PubSubManager_updatePubSubConfig] PubSub configured and active. "
                       "Disable the PublishSubscribe state before loading a pubsub configuration");
        return UA_STATUSCODE_BADINVALIDSTATE;
    }

    /* Ensure the PubSubManager is stopped before clearing */
    if(psm->sc.state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_INFO(psm->logging, UA_LOGCATEGORY_PUBSUB,
                    "[UA_PubSubManager_updatePubSubConfig] Stopping PubSubManager before loading configuration");
        UA_PubSubManager_setState(psm, UA_LIFECYCLESTATE_STOPPED);
    }

    /* Clear the PubSubManager to load a new config.
     * The PubSubManager is now guaranteed to be stopped. */
    UA_StatusCode res = UA_PubSubManager_clear(psm);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Configuration of Published DataSets: */
    UA_UInt32 pdsCount = (UA_UInt32)configurationParameters->publishedDataSetsSize;
    UA_NodeId *publishedDataSetIdent = (UA_NodeId*)UA_calloc(pdsCount, sizeof(UA_NodeId));
    if(!publishedDataSetIdent)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    for(UA_UInt32 i = 0; i < pdsCount; i++) {
        res = createPublishedDataSet(psm,
                                     &configurationParameters->publishedDataSets[i],
                                     &publishedDataSetIdent[i]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                         "[UA_PubSubManager_updatePubSubConfig] PDS creation failed");
            UA_free(publishedDataSetIdent);
            return res;
        }
    }

    /* Configuration of PubSub Connections: */
    if(configurationParameters->connectionsSize < 1) {
        UA_LOG_WARNING(psm->logging, UA_LOGCATEGORY_PUBSUB,
                       "[UA_PubSubManager_updatePubSubConfig] no connection in "
                       "UA_PubSubConfigurationDataType");
        UA_free(publishedDataSetIdent);
        return UA_STATUSCODE_GOOD;
    }

    /* Phase 1: Create all components with enabled = false to avoid premature state changes */
    UA_LOG_INFO(psm->logging, UA_LOGCATEGORY_PUBSUB,
                "[UA_PubSubManager_updatePubSubConfig] START CONNECTIONS (Phase 1: Creation)");

    /* Store connection NodeIds for Phase 2 */
    UA_NodeId *connectionIdents = (UA_NodeId*)UA_calloc(configurationParameters->connectionsSize, sizeof(UA_NodeId));
    if(!connectionIdents) {
        UA_free(publishedDataSetIdent);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for(size_t i = 0; i < configurationParameters->connectionsSize; i++) {
        res = createPubSubConnection(psm, &configurationParameters->connections[i],
                                     pdsCount, publishedDataSetIdent, &connectionIdents[i]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free(connectionIdents);
            break;
        }
    }
    
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(publishedDataSetIdent);
        return res;
    }
    
    /* Phase 2: Enable components based on original configuration */
    UA_LOG_INFO(psm->logging, UA_LOGCATEGORY_PUBSUB,
                "[UA_PubSubManager_updatePubSubConfig] START COMPONENTS (Phase 2: Enabling)");
    
    /* Enable connections and their child components */
    for(size_t i = 0; i < configurationParameters->connectionsSize; i++) {
        const UA_PubSubConnectionDataType *connParams = &configurationParameters->connections[i];
        
        if(connParams->enabled) {
            UA_PubSubConnection *conn = UA_PubSubConnection_find(psm, connectionIdents[i]);
            if(conn) {
                conn->config.enabled = true;                
                UA_WriterGroup *wg;
                size_t wgIndex = 0;
                LIST_FOREACH(wg, &conn->writerGroups, listEntry) {
                    if(wgIndex < connParams->writerGroupsSize && connParams->writerGroups[wgIndex].enabled) {
                        wg->config.enabled = true;
                        UA_DataSetWriter *dsw;
                        size_t dswIndex = 0;
                        LIST_FOREACH(dsw, &wg->writers, listEntry) {
                            if(dswIndex < connParams->writerGroups[wgIndex].dataSetWritersSize && 
                               connParams->writerGroups[wgIndex].dataSetWriters[dswIndex].enabled) {
                                dsw->config.enabled = true;
                            }
                            dswIndex++;
                        }
                    }
                    wgIndex++;
                }
                
                /* Enable reader groups */
                UA_ReaderGroup *rg;
                size_t rgIndex = 0;
                LIST_FOREACH(rg, &conn->readerGroups, listEntry) {
                    if(rgIndex < connParams->readerGroupsSize && connParams->readerGroups[rgIndex].enabled) {
                        rg->config.enabled = true;                        
                        UA_DataSetReader *dsr;
                        size_t dsrIndex = 0;
                        LIST_FOREACH(dsr, &rg->readers, listEntry) {
                            if(dsrIndex < connParams->readerGroups[rgIndex].dataSetReadersSize && 
                               connParams->readerGroups[rgIndex].dataSetReaders[dsrIndex].enabled) {
                                dsr->config.enabled = true;
                            }
                            dsrIndex++;
                        }
                    }
                    rgIndex++;
                }
            }
        }
    }

    /* Enable PubSubManager if specified */
    if(configurationParameters->enabled) {
        UA_LOG_INFO(psm->logging, UA_LOGCATEGORY_PUBSUB,
                       "[UA_PubSubManager_updatePubSubConfig] PubSubManager is enabled");
        UA_assert(psm->sc.state == UA_LIFECYCLESTATE_STOPPED);
        psm->pubSubInitialSetupMode = true;
        UA_PubSubManager_setState(psm, UA_LIFECYCLESTATE_STARTED);
        psm->pubSubInitialSetupMode = false;
    }
    
    UA_free(connectionIdents);
    UA_free(publishedDataSetIdent);
    return res;
}

static UA_StatusCode
createPubSubConnection(UA_PubSubManager *psm, const UA_PubSubConnectionDataType *connParams,
                       UA_UInt32 pdsCount, UA_NodeId *pdsIdent, UA_NodeId *connectionIdent) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PubSubConnectionConfig config;
    memset(&config, 0, sizeof(UA_PubSubConnectionConfig));

    config.name =                       connParams->name;
    config.transportProfileUri =        connParams->transportProfileUri;
    config.connectionProperties.map =   connParams->connectionProperties;
    config.connectionProperties.mapSize = connParams->connectionPropertiesSize;
    config.enabled = false;  /* Always create disabled, enabling during the last stage of updatePubSubConfig */

    UA_StatusCode res = UA_PublisherId_fromVariant(&config.publisherId,
                                                   &connParams->publisherId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createPubSubConnection] "
                     "Setting PublisherId failed");
        return res;
    }

    if(connParams->address.encoding == UA_EXTENSIONOBJECT_DECODED) {
        UA_Variant_setScalar(&(config.address),
                             connParams->address.content.decoded.data,
                             connParams->address.content.decoded.type);
    } else {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createPubSubConnection] "
                     "Reading connection address failed");
        UA_PublisherId_clear(&config.publisherId);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(connParams->transportSettings.encoding == UA_EXTENSIONOBJECT_DECODED) {
        UA_Variant_setScalar(&(config.connectionTransportSettings),
                             connParams->transportSettings.content.decoded.data,
                             connParams->transportSettings.content.decoded.type);
    } else if (connParams->transportSettings.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
        UA_LOG_WARNING(psm->logging, UA_LOGCATEGORY_PUBSUB,
                       "[UA_PubSubManager_createPubSubConnection] "
                       "TransportSettings can not be read");
    }

    res = UA_PubSubConnection_create(psm, &config, connectionIdent);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createPubSubConnection] "
                     "Connection creation failed");
        return res;
    }

    for(size_t i = 0; i < connParams->writerGroupsSize; i++) {
        createWriterGroup(psm, &connParams->writerGroups[i],
                          *connectionIdent, pdsCount, pdsIdent);
    }

    for(size_t j = 0; j < connParams->readerGroupsSize; j++) {
        createReaderGroup(psm, &connParams->readerGroups[j], *connectionIdent);
    }

    UA_PublisherId_clear(&config.publisherId);
    return UA_STATUSCODE_GOOD;
}

/* Function called by UA_PubSubManager_createWriterGroup to configure the messageSettings
 * of a writerGroup */
static UA_StatusCode
setWriterGroupEncodingType(UA_PubSubManager *psm,
                           const UA_WriterGroupDataType *writerGroupParameters,
                           UA_WriterGroupConfig *config) {
    if(writerGroupParameters->messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_setWriterGroupEncodingType] "
                     "getting message type information failed");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    if(writerGroupParameters->messageSettings.content.decoded.type ==
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]) {
        config->encodingMimeType = UA_PUBSUB_ENCODING_UADP;
    } else if(writerGroupParameters->messageSettings.content.decoded.type ==
              &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE]) {
#ifdef UA_ENABLE_JSON_ENCODING
        config->encodingMimeType = UA_PUBSUB_ENCODING_JSON;
#else
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_setWriterGroupEncodingType] "
                     "encoding type: JSON (not implemented!)");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
#endif
    } else {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_setWriterGroupEncodingType] "
                     "invalid message encoding type");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
createWriterGroup(UA_PubSubManager *psm,
                  const UA_WriterGroupDataType *writerGroupParameters,
                  UA_NodeId connectionIdent, UA_UInt32 pdsCount,
                  const UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_WriterGroupConfig config;
    memset(&config, 0, sizeof(UA_WriterGroupConfig));
    config.name =                  writerGroupParameters->name;
    config.writerGroupId =         writerGroupParameters->writerGroupId;
    config.publishingInterval =    writerGroupParameters->publishingInterval;
    config.keepAliveTime =         writerGroupParameters->keepAliveTime;
    config.priority =              writerGroupParameters->priority;
    config.securityMode =          writerGroupParameters->securityMode;
    config.transportSettings =     writerGroupParameters->transportSettings;
    config.messageSettings =       writerGroupParameters->messageSettings;
    config.groupProperties.mapSize =   writerGroupParameters->groupPropertiesSize;
    config.groupProperties.map =   writerGroupParameters->groupProperties;
    config.maxEncapsulatedDataSetMessageCount = 255; /* non std parameter */
    config.enabled = false;  /* Always create disabled, enabling during the last stage of updatePubSubConfig */

    UA_StatusCode res = setWriterGroupEncodingType(psm, writerGroupParameters, &config);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createWriterGroup] "
                     "Setting message settings failed");
        return res;
    }

    /* Load config. The enabled flag is "false" here.
     * Auto-enable only after adding the DataSetWriters. */
    UA_NodeId writerGroupIdent;
    res = UA_WriterGroup_create(psm, connectionIdent, &config, &writerGroupIdent);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createWriterGroup] "
                     "Adding WriterGroup failed: 0x%x", res);
        return res;
    }

    /* Configuration of all DataSetWriters that belong to this WriterGroup - all created disabled */
    for(size_t dsw = 0; dsw < writerGroupParameters->dataSetWritersSize; dsw++) {
        createDataSetWriter(psm, &writerGroupParameters->dataSetWriters[dsw],
                            writerGroupIdent, pdsCount, pdsIdent);
    }

    return res;
}

static UA_StatusCode
createDataSetWriter(UA_PubSubManager *psm,
                    const UA_DataSetWriterDataType *dataSetWriterParameters,
                    UA_NodeId writerGroupIdent, UA_UInt32 pdsCount,
                    const UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Search the PDS among the supplied PDS-NodeIds.
     * The name must match the configured one. */
    UA_PublishedDataSet *pds = NULL;
    size_t i = 0;
    for(; i < pdsCount; i++) {
        pds = UA_PublishedDataSet_find(psm, pdsIdent[i]);
        if(!pds)
            continue;
        if(!UA_String_equal(&dataSetWriterParameters->dataSetName,
                            &pds->config.name))
           continue;
        break;
    }

    /* No matching PDS found */
    if(i == pdsCount) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_addDataSetWriterWithPdsReference] "
                     "No matching PDS with name %S found",
                     dataSetWriterParameters->name);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_DataSetWriterConfig config;
    memset(&config, 0, sizeof(UA_DataSetWriterConfig));
    config.name = dataSetWriterParameters->name;
    config.dataSetWriterId = dataSetWriterParameters->dataSetWriterId;
    config.keyFrameCount = dataSetWriterParameters->keyFrameCount;
    config.dataSetFieldContentMask = dataSetWriterParameters->dataSetFieldContentMask;
    config.messageSettings = dataSetWriterParameters->messageSettings;
    config.dataSetName = dataSetWriterParameters->dataSetName;
    config.dataSetWriterProperties.mapSize = dataSetWriterParameters->dataSetWriterPropertiesSize;
    config.dataSetWriterProperties.map = dataSetWriterParameters->dataSetWriterProperties;
    config.enabled = false;  /* Always create disabled, enabling during the last stage of updatePubSubConfig */

    /* Create the DataSetWriter disabled. Enable later in Phase 2. */
    UA_NodeId dataSetWriterIdent;
    UA_StatusCode res =
        UA_DataSetWriter_create(psm, writerGroupIdent, pdsIdent[i],
                                &config, &dataSetWriterIdent);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_addDataSetWriterWithPdsReference] "
                     "Creating the DataSetWriter for %S failed",
                     dataSetWriterParameters->name);
    }
    return res;
}

static UA_StatusCode
createReaderGroup(UA_PubSubManager *psm,
                  const UA_ReaderGroupDataType *readerGroupParameters,
                  UA_NodeId connectionIdent) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_ReaderGroupConfig config;
    memset(&config, 0, sizeof(UA_ReaderGroupConfig));

    config.name = readerGroupParameters->name;
    config.securityMode = readerGroupParameters->securityMode;
    config.enabled = false;  /* Always create disabled, enabling during the last stage of updatePubSubConfig */

    UA_NodeId readerGroupIdent;
    UA_StatusCode res = UA_ReaderGroup_create(psm, connectionIdent,
                                              &config, &readerGroupIdent);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createReaderGroup] Adding ReaderGroup "
                     "failed: 0x%x", res);
        return res;
    }

    for(UA_UInt32 i = 0; i < readerGroupParameters->dataSetReadersSize; i++) {
        createDataSetReader(psm, &readerGroupParameters->dataSetReaders[i],
                            readerGroupIdent);
    }

    return UA_STATUSCODE_GOOD;
}

/* Creates TargetVariables or SubscribedDataSetMirror for a given DataSetReader */
static UA_StatusCode
addSubscribedDataSet(UA_PubSubManager *psm, const UA_NodeId dsReaderIdent,
                     const UA_ExtensionObject *subscribedDataSet) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    if(subscribedDataSet->content.decoded.type ==
       &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE]) {
        UA_TargetVariablesDataType *targetVars = (UA_TargetVariablesDataType*)
            subscribedDataSet->content.decoded.data;
        UA_StatusCode res = UA_STATUSCODE_BADINTERNALERROR;
        UA_DataSetReader *dsr = UA_DataSetReader_find(psm, dsReaderIdent);
        if(dsr)
            res = DataSetReader_createTargetVariables(psm, dsr,
                                                      targetVars->targetVariablesSize,
                                                      targetVars->targetVariables);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                         "[UA_PubSubManager_addSubscribedDataSet] "
                         "create TargetVariables failed");
        }
        return res;
    }

    if(subscribedDataSet->content.decoded.type ==
       &UA_TYPES[UA_TYPES_SUBSCRIBEDDATASETMIRRORDATATYPE]) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_addSubscribedDataSet] "
                     "DataSetMirror is currently not supported");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                 "[UA_PubSubManager_addSubscribedDataSet] "
                 "Invalid Type of SubscribedDataSet");
    return UA_STATUSCODE_BADINTERNALERROR;
}

static UA_StatusCode
createDataSetReader(UA_PubSubManager *psm, const UA_DataSetReaderDataType *dsrParams,
                    UA_NodeId readerGroupIdent) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    /* Prepare the config parameters */
    UA_DataSetReaderConfig config;
    memset(&config, 0, sizeof(UA_DataSetReaderConfig));
    config.name = dsrParams->name;
    config.writerGroupId = dsrParams->writerGroupId;
    config.dataSetWriterId = dsrParams->dataSetWriterId;
    config.dataSetMetaData = dsrParams->dataSetMetaData;
    config.dataSetFieldContentMask = dsrParams->dataSetFieldContentMask;
    config.messageReceiveTimeout =  dsrParams->messageReceiveTimeout;
    config.messageSettings = dsrParams->messageSettings;
    config.enabled = false;  /* Always create disabled, enabling during the last stage of updatePubSubConfig */
    UA_StatusCode res = UA_PublisherId_fromVariant(&config.publisherId,
                                                   &dsrParams->publisherId);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_NodeId dsReaderIdent;
    res = UA_DataSetReader_create(psm, readerGroupIdent, &config, &dsReaderIdent);
    UA_PublisherId_clear(&config.publisherId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createDataSetReader] "
                     "Could not create the DataSetReader");
        return res;
    }

    /* Create the SubscribedDataSet */
    res = addSubscribedDataSet(psm, dsReaderIdent, &dsrParams->subscribedDataSet);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createDataSetReader] "
                     "Create subscribedDataSet failed");
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

/* Determines whether PublishedDataSet is of type PublishedItems or PublishedEvents.
 * (PublishedEvents are currently not supported!)
 *
 * @param publishedDataSetParameters PublishedDataSet parameters
 * @param config PublishedDataSet configuration object */
static UA_StatusCode
setPublishedDataSetType(UA_PubSubManager *psm,
                        const UA_PublishedDataSetDataType *pdsParams,
                        UA_PublishedDataSetConfig *config) {
    if(pdsParams->dataSetSource.encoding != UA_EXTENSIONOBJECT_DECODED)
        return UA_STATUSCODE_BADINTERNALERROR;

    const UA_DataType *sourceType = pdsParams->dataSetSource.content.decoded.type;
    if(sourceType == &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE]) {
        config->publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
        return UA_STATUSCODE_GOOD;
    } else if(sourceType == &UA_TYPES[UA_TYPES_PUBLISHEDEVENTSDATATYPE]) {
        /* config.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDEVENTS; */
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_setPublishedDataSetType] Published events not supported.");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                 "[UA_PubSubManager_setPublishedDataSetType] Invalid DataSetSourceDataType.");
    return UA_STATUSCODE_BADINTERNALERROR;
}

/* Creates PublishedDataSetConfig object from PublishedDataSet object
 *
 * @param psm PubSubManager that shall be configured
 * @param pdsParams publishedDataSet configuration
 * @param pdsIdent NodeId of the publishedDataSet */
static UA_StatusCode
createPublishedDataSet(UA_PubSubManager *psm,
                       const UA_PublishedDataSetDataType *pdsParams,
                       UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PublishedDataSetConfig config;
    memset(&config, 0, sizeof(UA_PublishedDataSetConfig));

    config.name = pdsParams->name;
    UA_StatusCode res = setPublishedDataSetType(psm, pdsParams, &config);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = UA_PublishedDataSet_create(psm, &config, pdsIdent).addResult;
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createPublishedDataSet] "
                     "Adding PublishedDataSet failed.");
        return res;
    }

    /* DataSetField configuration for this publishedDataSet: */
    res = createDataSetFields(psm, pdsIdent, pdsParams);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createPublishedDataSet] "
                     "Creating DataSetFieldConfig failed.");
    }

    return res;
}

/* Adds DataSetField Variables bound to a certain PublishedDataSet. This method does NOT
 * check, whether the PublishedDataSet actually contains Variables instead of Events!
 *
 * @param psm PubSubManager that shall be configured
 * @param pdsIdent NodeId of the publishedDataSet, the DataSetField belongs to
 * @param publishedDataSetParameters publishedDataSet configuration */
static UA_StatusCode
addDataSetFieldVariables(UA_PubSubManager *psm, const UA_NodeId *pdsIdent,
                         const UA_PublishedDataSetDataType *pdsParams) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PublishedDataItemsDataType *pdItems = (UA_PublishedDataItemsDataType *)
        pdsParams->dataSetSource.content.decoded.data;
    if(pdItems->publishedDataSize != pdsParams->dataSetMetaData.fieldsSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    for(size_t i = 0; i < pdItems->publishedDataSize; i++) {
        UA_DataSetFieldConfig fc;
        memset(&fc, 0, sizeof(UA_DataSetFieldConfig));
        fc.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
        fc.field.variable.configurationVersion =
            pdsParams->dataSetMetaData.configurationVersion;
        fc.field.variable.fieldNameAlias = pdsParams->dataSetMetaData.fields[i].name;
        fc.field.variable.promotedField = pdsParams->dataSetMetaData.
            fields[i].fieldFlags & 0x0001;
        fc.field.variable.publishParameters = pdItems->publishedData[i];

        UA_NodeId fieldIdent;
        UA_StatusCode res = UA_DataSetField_create(psm, *pdsIdent, &fc, &fieldIdent).result;
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                         "[UA_PubSubManager_addDataSetFieldVariables] "
                         "Adding DataSetField Variable failed.");
            return res;
        }
    }

    return UA_STATUSCODE_GOOD;
}

/* Checks if PublishedDataSet contains event or variable fields and calls the
 * corresponding method to add these fields.
 *
 * @param psm PubSubManager that shall be configured
 * @param pdsIdent NodeId of the publishedDataSet, the DataSetFields belongs to
 * @param pdsParams publishedDataSet configuration */
static UA_StatusCode
createDataSetFields(UA_PubSubManager *psm, const UA_NodeId *pdsIdent,
                    const UA_PublishedDataSetDataType *pdsParams) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    if(pdsParams->dataSetSource.encoding != UA_EXTENSIONOBJECT_DECODED)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(pdsParams->dataSetSource.content.decoded.type ==
       &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE])
        return addDataSetFieldVariables(psm, pdsIdent, pdsParams);

    /* TODO: Implement Routine for adding Event DataSetFields */
    if(pdsParams->dataSetSource.content.decoded.type ==
       &UA_TYPES[UA_TYPES_PUBLISHEDEVENTSDATATYPE]) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_createDataSetFields] "
                     "Published events not supported.");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                 "[UA_PubSubManager_createDataSetFields] "
                 "Invalid DataSetSourceDataType.");
    return UA_STATUSCODE_BADINTERNALERROR;
}

UA_StatusCode
UA_Server_loadPubSubConfigFromByteString(UA_Server *server, const UA_ByteString buffer) {
    size_t offset = 0;
    UA_ExtensionObject decodedFile;

    if(server == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_Server_loadPubSubConfigFromByteString] Invalid argument");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    lockServer(server);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode res =
        UA_ExtensionObject_decodeBinary(&buffer, &offset, &decodedFile);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_decodeBinFile] decoding UA_Binary failed");
        goto cleanup;
    }

    UA_PubSubConfigurationDataType *pubSubConfig = NULL;
    res = extractPubSubConfigFromExtensionObject(psm, &decodedFile, &pubSubConfig);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_loadPubSubConfigFromByteString] "
                     "Extracting PubSub Configuration failed");
        goto cleanup;
    }

    res = updatePubSubConfig(psm, pubSubConfig);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_loadPubSubConfigFromByteString] "
                     "Loading PubSub configuration failed");
        goto cleanup;
    }

 cleanup:
    unlockServer(server);
    UA_ExtensionObject_clear(&decodedFile);
    return res;
}

/* Encodes a PubSubConfigurationDataType object as ByteString using the UA Binary Data
 * Encoding */
static UA_StatusCode
encodePubSubConfiguration(UA_PubSubManager *psm,
                          UA_PubSubConfigurationDataType *configurationParameters,
                          UA_ByteString *buffer) {
    UA_UABinaryFileDataType binFile;
    memset(&binFile, 0, sizeof(UA_UABinaryFileDataType));
    /*Perhaps, additional initializations of binFile are necessary here.*/

    UA_Variant_setScalar(&binFile.body, configurationParameters,
                         &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONDATATYPE]);

    UA_ExtensionObject container;
    memset(&container, 0, sizeof(UA_ExtensionObject));
    container.encoding = UA_EXTENSIONOBJECT_DECODED;
    container.content.decoded.type = &UA_TYPES[UA_TYPES_UABINARYFILEDATATYPE];
    container.content.decoded.data = &binFile;

    size_t fileSize = UA_ExtensionObject_calcSizeBinary(&container);
    buffer->data = (UA_Byte*)UA_calloc(fileSize, sizeof(UA_Byte));
    if(buffer->data == NULL) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_encodePubSubConfiguration] Allocating buffer failed");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    buffer->length = fileSize;

    UA_Byte *bufferPos = buffer->data;
    UA_StatusCode res =
        UA_ExtensionObject_encodeBinary(&container, &bufferPos, bufferPos + fileSize);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "[UA_PubSubManager_encodePubSubConfiguration] Encoding failed");
    }
    return res;
}

static UA_StatusCode
generatePublishedDataSetDataType(UA_PubSubManager *psm,
                                 const UA_PublishedDataSet *src,
                                 UA_PublishedDataSetDataType *dst) {
    if(src->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    memset(dst, 0, sizeof(UA_PublishedDataSetDataType));

    UA_PublishedDataItemsDataType *tmp = UA_PublishedDataItemsDataType_new();
    UA_String_copy(&src->config.name, &dst->name);
    dst->dataSetMetaData.fieldsSize = src->fieldSize;

    size_t index = 0;
    tmp->publishedDataSize = src->fieldSize;
    tmp->publishedData = (UA_PublishedVariableDataType*)
        UA_Array_new(tmp->publishedDataSize, &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
    if(tmp->publishedData == NULL) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB, "Allocation memory failed");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->dataSetMetaData.fields = (UA_FieldMetaData*)
        UA_Array_new(dst->dataSetMetaData.fieldsSize, &UA_TYPES[UA_TYPES_FIELDMETADATA]);
    if(dst->dataSetMetaData.fields == NULL) {
        UA_free(tmp->publishedData);
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB, "Allocation memory failed");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_DataSetField *dsf, *dsf_tmp = NULL;
    TAILQ_FOREACH_SAFE(dsf ,&src->fields, listEntry, dsf_tmp) {
        UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
                       &dst->dataSetMetaData.fields[index].name);
        UA_PublishedVariableDataType_copy(&dsf->config.field.variable.publishParameters,
                                          &tmp->publishedData[index]);
        UA_ConfigurationVersionDataType_copy(&dsf->config.field.variable.configurationVersion,
                                             &dst->dataSetMetaData.configurationVersion);
        dst->dataSetMetaData.fields[index].fieldFlags =
            dsf->config.field.variable.promotedField;
        index++;
    }
    UA_ExtensionObject_setValue(&dst->dataSetSource, tmp,
                                &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE]);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
generateDataSetWriterDataType(const UA_DataSetWriter *src,
                              UA_DataSetWriterDataType *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memset(dst, 0, sizeof(UA_DataSetWriterDataType));
    res |= UA_String_copy(&src->config.name, &dst->name);
    dst->dataSetWriterId = src->config.dataSetWriterId;
    dst->keyFrameCount = src->config.keyFrameCount;
    dst->dataSetFieldContentMask = src->config.dataSetFieldContentMask;
    res |= UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings);
    res |= UA_String_copy(&src->config.dataSetName, &dst->dataSetName);
    if(res != UA_STATUSCODE_GOOD) {
        UA_DataSetWriterDataType_clear(dst);
        return res;
    }

    res = UA_Array_copy(src->config.dataSetWriterProperties.map,
                        src->config.dataSetWriterProperties.mapSize,
                        (void**)&dst->dataSetWriterProperties,
                        &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res == UA_STATUSCODE_GOOD)
        dst->dataSetWriterPropertiesSize = src->config.dataSetWriterProperties.mapSize;
    else
        UA_DataSetWriterDataType_clear(dst);

    return res;
}

static UA_StatusCode
generateWriterGroupDataType(const UA_WriterGroup *src,
                            UA_WriterGroupDataType *dst) {
    memset(dst, 0, sizeof(UA_WriterGroupDataType));

    UA_String_copy(&src->config.name, &dst->name);
    dst->writerGroupId = src->config.writerGroupId;
    dst->publishingInterval = src->config.publishingInterval;
    dst->keepAliveTime = src->config.keepAliveTime;
    dst->priority = src->config.priority;
    dst->securityMode = src->config.securityMode;

    UA_ExtensionObject_copy(&src->config.transportSettings, &dst->transportSettings);
    UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings);

    UA_StatusCode res =
        UA_Array_copy(src->config.groupProperties.map,
                      src->config.groupProperties.mapSize,
                      (void**)&dst->groupProperties,
                      &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res != UA_STATUSCODE_GOOD) {
        UA_WriterGroupDataType_clear(dst);
        return res;
    }
    dst->groupPropertiesSize = src->config.groupProperties.mapSize,

    dst->dataSetWriters = (UA_DataSetWriterDataType*)
        UA_calloc(src->writersCount, sizeof(UA_DataSetWriterDataType));
    if(!dst->dataSetWriters) {
        UA_WriterGroupDataType_clear(dst);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->dataSetWritersSize = src->writersCount;

    UA_DataSetWriter *dsw;
    size_t dsWriterIndex = 0;
    LIST_FOREACH(dsw, &src->writers, listEntry) {
        res |= generateDataSetWriterDataType(dsw, &dst->dataSetWriters[dsWriterIndex]);
        dsWriterIndex++;
    }
    if(res != UA_STATUSCODE_GOOD)
        UA_WriterGroupDataType_clear(dst);
    return res;
}

static UA_StatusCode
generateDataSetReaderDataType(const UA_DataSetReader *src,
                              UA_DataSetReaderDataType *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memset(dst, 0, sizeof(UA_DataSetReaderDataType));
    dst->writerGroupId = src->config.writerGroupId;
    dst->dataSetWriterId = src->config.dataSetWriterId;
    dst->dataSetFieldContentMask = src->config.dataSetFieldContentMask;
    dst->messageReceiveTimeout = src->config.messageReceiveTimeout;
    res |= UA_String_copy(&src->config.name, &dst->name);
    res |= UA_DataSetMetaDataType_copy(&src->config.dataSetMetaData,
                                       &dst->dataSetMetaData);
    res |= UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings);

    UA_Variant var;
    UA_PublisherId_toVariant(&src->config.publisherId, &var);
    res |= UA_Variant_copy(&var, &dst->publisherId);

    UA_TargetVariablesDataType *tmpTarget = UA_TargetVariablesDataType_new();
    if(!tmpTarget)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    const UA_TargetVariablesDataType *targets = &src->config.subscribedDataSet.target;
    tmpTarget->targetVariables = (UA_FieldTargetDataType *)
        UA_calloc(targets->targetVariablesSize, sizeof(UA_FieldTargetDataType));
    if(!tmpTarget->targetVariables)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    tmpTarget->targetVariablesSize = targets->targetVariablesSize;
    for(size_t i = 0; i < tmpTarget->targetVariablesSize; i++) {
        res |= UA_FieldTargetDataType_copy(&targets->targetVariables[i],
                                           &tmpTarget->targetVariables[i]);
    }

    UA_ExtensionObject_setValue(&dst->subscribedDataSet, tmpTarget,
                                &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE]);

    return res;
}

static UA_StatusCode
generateReaderGroupDataType(const UA_ReaderGroup *src,
                            UA_ReaderGroupDataType *dst) {
    memset(dst, 0, sizeof(UA_ReaderGroupDataType));

    UA_String_copy(&src->config.name, &dst->name);
    dst->dataSetReaders = (UA_DataSetReaderDataType*)
        UA_calloc(src->readersCount, sizeof(UA_DataSetReaderDataType));
    if(dst->dataSetReaders == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    dst->dataSetReadersSize = src->readersCount;

    size_t i = 0;
    UA_DataSetReader *dsr, *dsr_tmp = NULL;
    LIST_FOREACH_SAFE(dsr, &src->readers, listEntry, dsr_tmp) {
        UA_StatusCode res =
            generateDataSetReaderDataType(dsr, &dst->dataSetReaders[i]);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        i++;
    }

    return UA_STATUSCODE_GOOD;
}

/* Generates a PubSubConnectionDataType object from a PubSubConnection. */
static UA_StatusCode
generatePubSubConnectionDataType(UA_PubSubManager *psm,
                                 const UA_PubSubConnection *src,
                                 UA_PubSubConnectionDataType *dst) {
    const UA_DataType *publisherIdType;
    memset(dst, 0, sizeof(UA_PubSubConnectionDataType));

    UA_String_copy(&src->config.name, &dst->name);
    UA_String_copy(&src->config.transportProfileUri, &dst->transportProfileUri);

    UA_StatusCode res =
        UA_Array_copy(src->config.connectionProperties.map,
                      src->config.connectionProperties.mapSize,
                      (void**)&dst->connectionProperties,
                      &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res != UA_STATUSCODE_GOOD) {
        UA_PubSubConnectionDataType_clear(dst);
        return res;
    }
    dst->connectionPropertiesSize = src->config.connectionProperties.mapSize;

    switch (src->config.publisherId.idType) {
        case UA_PUBLISHERIDTYPE_BYTE:
            publisherIdType = &UA_TYPES[UA_TYPES_BYTE];
            break;
        case UA_PUBLISHERIDTYPE_UINT16:
            publisherIdType = &UA_TYPES[UA_TYPES_UINT16];
            break;
        case UA_PUBLISHERIDTYPE_UINT32:
            publisherIdType = &UA_TYPES[UA_TYPES_UINT32];
            break;
        case UA_PUBLISHERIDTYPE_UINT64:
            publisherIdType = &UA_TYPES[UA_TYPES_UINT64];
            break;
        case UA_PUBLISHERIDTYPE_STRING:
            publisherIdType = &UA_TYPES[UA_TYPES_STRING];
            break;
        default:
            UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                         "generatePubSubConnectionDataType(): publisher Id type is not supported");
            return UA_STATUSCODE_BADINTERNALERROR;
            break;
    }
    UA_Variant_setScalarCopy(&dst->publisherId,
                             &src->config.publisherId.id,
                             publisherIdType);

    /* Possibly, array size and dimensions of src->config->address and
     * src->config->connectionTransportSettings should be checked beforehand. */
    dst->address.encoding = UA_EXTENSIONOBJECT_DECODED;
    dst->address.content.decoded.type = src->config.address.type;
    res = UA_Array_copy(src->config.address.data, 1,
                        &dst->address.content.decoded.data,
                        src->config.address.type);
    if(res != UA_STATUSCODE_GOOD) {
        UA_PubSubConnectionDataType_clear(dst);
        return res;
    }

    if(src->config.connectionTransportSettings.data) {
        dst->transportSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
        dst->transportSettings.content.decoded.type =
            src->config.connectionTransportSettings.type;
        res = UA_Array_copy(src->config.connectionTransportSettings.data, 1,
                            &dst->transportSettings.content.decoded.data,
                            src->config.connectionTransportSettings.type);

        if(res != UA_STATUSCODE_GOOD) {
            UA_PubSubConnectionDataType_clear(dst);
            return res;
        }
    }

    dst->writerGroups = (UA_WriterGroupDataType*)
        UA_calloc(src->writerGroupsSize, sizeof(UA_WriterGroupDataType));
    if(!dst->writerGroups) {
        UA_PubSubConnectionDataType_clear(dst);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->writerGroupsSize = src->writerGroupsSize;
    UA_WriterGroup *wg, *wg_tmp = NULL;
    size_t wgIndex = 0;
    LIST_FOREACH_SAFE(wg, &src->writerGroups, listEntry, wg_tmp) {
        res = generateWriterGroupDataType(wg, &dst->writerGroups[wgIndex]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_PubSubConnectionDataType_clear(dst);
            return res;
        }
        wgIndex++;
    }

    dst->readerGroups = (UA_ReaderGroupDataType*)
        UA_calloc(src->readerGroupsSize, sizeof(UA_ReaderGroupDataType));
    if(dst->readerGroups == NULL) {
        UA_PubSubConnectionDataType_clear(dst);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->readerGroupsSize = src->readerGroupsSize;
    UA_ReaderGroup *rg = NULL;
    size_t rgIndex = 0;
    LIST_FOREACH(rg, &src->readerGroups, listEntry) {
        res = generateReaderGroupDataType(rg, &dst->readerGroups[rgIndex]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_PubSubConnectionDataType_clear(dst);
            return res;
        }
        rgIndex++;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
generatePubSubConfigurationDataType(UA_PubSubManager *psm,
                                    UA_PubSubConfigurationDataType *configDT) {
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);

    UA_PubSubConfigurationDataType_init(configDT);
    configDT->publishedDataSets = (UA_PublishedDataSetDataType*)
        UA_calloc(psm->publishedDataSetsSize,
                  sizeof(UA_PublishedDataSetDataType));
    if(configDT->publishedDataSets == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    configDT->publishedDataSetsSize = psm->publishedDataSetsSize;

    UA_PublishedDataSet *pds;
    UA_UInt32 pdsIndex = 0;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    TAILQ_FOREACH(pds, &psm->publishedDataSets, listEntry) {
        UA_PublishedDataSetDataType *dst = &configDT->publishedDataSets[pdsIndex];
        res = generatePublishedDataSetDataType(psm, pds, dst);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                         "[UA_PubSubManager_generatePubSubConfigurationDataType] "
                         "retrieving PublishedDataSet configuration failed");
            return res;
        }
        pdsIndex++;
    }

    configDT->connections = (UA_PubSubConnectionDataType*)
        UA_calloc(psm->connectionsSize, sizeof(UA_PubSubConnectionDataType));
    if(configDT->connections == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    configDT->connectionsSize = psm->connectionsSize;

    UA_UInt32 connectionIndex = 0;
    UA_PubSubConnection *connection;
    TAILQ_FOREACH(connection, &psm->connections, listEntry) {
        UA_PubSubConnectionDataType *cdt = &configDT->connections[connectionIndex];
        res = generatePubSubConnectionDataType(psm, connection, cdt);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                         "[UA_PubSubManager_generatePubSubConfigurationDataType] "
                         "retrieving PubSubConnection configuration failed");
            return res;
        }
        connectionIndex++;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_writePubSubConfigurationToByteString(UA_Server *server,
                                               UA_ByteString *buffer) {
    if(server == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_Server_writePubSubConfigurationToByteString] Invalid argument");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    lockServer(server);

    UA_PubSubManager *psm = getPSM(server);
    if(!psm) {
        unlockServer(server);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_PubSubConfigurationDataType config;
    UA_PubSubConfigurationDataType_init(&config);

    UA_StatusCode res = generatePubSubConfigurationDataType(psm, &config);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "Retrieving PubSub configuration failed");
        goto cleanup;
    }

    res = encodePubSubConfiguration(psm, &config, buffer);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(psm->logging, UA_LOGCATEGORY_PUBSUB,
                     "encoding PubSub configuration failed");
        goto cleanup;
    }

    UA_LOG_INFO(psm->logging, UA_LOGCATEGORY_PUBSUB,
                "Saving PubSub config was successful");

 cleanup:
    unlockServer(server);
    UA_PubSubConfigurationDataType_clear(&config);
    return res;
}

#endif /* UA_ENABLE_PUBSUB && UA_ENABLE_PUBSUB_FILE_CONFIG */

/**** amalgamated original file "/deps/yxml.c" ****/

/* This file is generated by yxml-gen.pl using yxml-states and yxml.c.in as input files.
 * It is preferable to edit those files instead of this one if you want to make a change.
 * The source files can be found through the homepage: https://dev.yorhel.nl/yxml */

/* Copyright (c) 2013-2014 Yoran Heling

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:

  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <string.h>

typedef enum {
	YXMLS_string,
	YXMLS_attr0,
	YXMLS_attr1,
	YXMLS_attr2,
	YXMLS_attr3,
	YXMLS_attr4,
	YXMLS_cd0,
	YXMLS_cd1,
	YXMLS_cd2,
	YXMLS_comment0,
	YXMLS_comment1,
	YXMLS_comment2,
	YXMLS_comment3,
	YXMLS_comment4,
	YXMLS_dt0,
	YXMLS_dt1,
	YXMLS_dt2,
	YXMLS_dt3,
	YXMLS_dt4,
	YXMLS_elem0,
	YXMLS_elem1,
	YXMLS_elem2,
	YXMLS_elem3,
	YXMLS_enc0,
	YXMLS_enc1,
	YXMLS_enc2,
	YXMLS_enc3,
	YXMLS_etag0,
	YXMLS_etag1,
	YXMLS_etag2,
	YXMLS_init,
	YXMLS_le0,
	YXMLS_le1,
	YXMLS_le2,
	YXMLS_le3,
	YXMLS_lee1,
	YXMLS_lee2,
	YXMLS_leq0,
	YXMLS_misc0,
	YXMLS_misc1,
	YXMLS_misc2,
	YXMLS_misc2a,
	YXMLS_misc3,
	YXMLS_pi0,
	YXMLS_pi1,
	YXMLS_pi2,
	YXMLS_pi3,
	YXMLS_pi4,
	YXMLS_std0,
	YXMLS_std1,
	YXMLS_std2,
	YXMLS_std3,
	YXMLS_ver0,
	YXMLS_ver1,
	YXMLS_ver2,
	YXMLS_ver3,
	YXMLS_xmldecl0,
	YXMLS_xmldecl1,
	YXMLS_xmldecl2,
	YXMLS_xmldecl3,
	YXMLS_xmldecl4,
	YXMLS_xmldecl5,
	YXMLS_xmldecl6,
	YXMLS_xmldecl7,
	YXMLS_xmldecl8,
	YXMLS_xmldecl9
} yxml_state_t;

#define yxml_isChar(c) 1
/* 0xd should be part of SP, too, but yxml_parse() already normalizes that into 0xa */
#define yxml_isSP(c) (c == 0x20 || c == 0x09 || c == 0x0a)
#define yxml_isAlpha(c) ((c|32)-'a' < 26)
#define yxml_isNum(c) (c-'0' < 10)
#define yxml_isHex(c) (yxml_isNum(c) || (c|32)-'a' < 6)
#define yxml_isEncName(c) (yxml_isAlpha(c) || yxml_isNum(c) || c == '.' || c == '_' || c == '-')
#define yxml_isNameStart(c) (yxml_isAlpha(c) || c == ':' || c == '_' || c >= 128)
#define yxml_isName(c) (yxml_isNameStart(c) || yxml_isNum(c) || c == '-' || c == '.')
/* XXX: The valid characters are dependent on the quote char, hence the access to x->quote */
#define yxml_isAttValue(c) (yxml_isChar(c) && c != x->quote && c != '<' && c != '&')
/* Anything between '&' and ';', the yxml_ref* functions will do further
 * validation. Strictly speaking, this is "yxml_isName(c) || c == '#'", but
 * this parser doesn't understand entities with '.', ':', etc, anwyay.  */
#define yxml_isRef(c) (yxml_isNum(c) || yxml_isAlpha(c) || c == '#')

#define INTFROM5CHARS(a, b, c, d, e) ((((uint64_t)(a))<<32) | (((uint64_t)(b))<<24) | (((uint64_t)(c))<<16) | (((uint64_t)(d))<<8) | (uint64_t)(e))

/* Set the given char value to ch (0<=ch<=255). */
static inline void yxml_setchar(char *dest, unsigned ch) {
	*(unsigned char *)dest = (unsigned char)ch;
}

/* Similar to yxml_setchar(), but will convert ch (any valid unicode point) to
 * UTF-8 and appends a '\0'. dest must have room for at least 5 bytes. */
static void yxml_setutf8(char *dest, unsigned ch) {
	if(ch <= 0x007F)
		yxml_setchar(dest++, ch);
	else if(ch <= 0x07FF) {
		yxml_setchar(dest++, 0xC0 | (ch>>6));
		yxml_setchar(dest++, 0x80 | (ch & 0x3F));
	} else if(ch <= 0xFFFF) {
		yxml_setchar(dest++, 0xE0 | (ch>>12));
		yxml_setchar(dest++, 0x80 | ((ch>>6) & 0x3F));
		yxml_setchar(dest++, 0x80 | (ch & 0x3F));
	} else {
		yxml_setchar(dest++, 0xF0 | (ch>>18));
		yxml_setchar(dest++, 0x80 | ((ch>>12) & 0x3F));
		yxml_setchar(dest++, 0x80 | ((ch>>6) & 0x3F));
		yxml_setchar(dest++, 0x80 | (ch & 0x3F));
	}
	*dest = 0;
}

static inline yxml_ret_t yxml_datacontent(yxml_t *x, unsigned ch) {
	yxml_setchar(x->data, ch);
	x->data[1] = 0;
	return YXML_CONTENT;
}

static inline yxml_ret_t yxml_datapi1(yxml_t *x, unsigned ch) {
	yxml_setchar(x->data, ch);
	x->data[1] = 0;
	return YXML_PICONTENT;
}

static inline yxml_ret_t yxml_datapi2(yxml_t *x, unsigned ch) {
	x->data[0] = '?';
	yxml_setchar(x->data+1, ch);
	x->data[2] = 0;
	return YXML_PICONTENT;
}

static inline yxml_ret_t yxml_datacd1(yxml_t *x, unsigned ch) {
	x->data[0] = ']';
	yxml_setchar(x->data+1, ch);
	x->data[2] = 0;
	return YXML_CONTENT;
}

static inline yxml_ret_t yxml_datacd2(yxml_t *x, unsigned ch) {
	x->data[0] = ']';
	x->data[1] = ']';
	yxml_setchar(x->data+2, ch);
	x->data[3] = 0;
	return YXML_CONTENT;
}

static inline yxml_ret_t yxml_dataattr(yxml_t *x, unsigned ch) {
	/* Normalize attribute values according to the XML spec section 3.3.3. */
	yxml_setchar(x->data, ch == 0x9 || ch == 0xa ? 0x20 : ch);
	x->data[1] = 0;
	return YXML_ATTRVAL;
}

static yxml_ret_t yxml_pushstack(yxml_t *x, char **res, unsigned ch) {
	if(x->stacklen+2 >= x->stacksize)
		return YXML_ESTACK;
	x->stacklen++;
	*res = (char *)x->stack+x->stacklen;
	x->stack[x->stacklen] = (unsigned char)ch;
	x->stacklen++;
	x->stack[x->stacklen] = 0;
	return YXML_OK;
}

static yxml_ret_t yxml_pushstackc(yxml_t *x, unsigned ch) {
	if(x->stacklen+1 >= x->stacksize)
		return YXML_ESTACK;
	x->stack[x->stacklen] = (unsigned char)ch;
	x->stacklen++;
	x->stack[x->stacklen] = 0;
	return YXML_OK;
}

static void yxml_popstack(yxml_t *x) {
	do
		x->stacklen--;
	while(x->stack[x->stacklen]);
}

static inline yxml_ret_t yxml_elemstart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->elem, ch); }
static inline yxml_ret_t yxml_elemname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
static inline yxml_ret_t yxml_elemnameend(yxml_t *x, unsigned ch) { return YXML_ELEMSTART; }

/* Also used in yxml_elemcloseend(), since this function just removes the last
 * element from the stack and returns ELEMEND. */
static yxml_ret_t yxml_selfclose(yxml_t *x, unsigned ch) {
	yxml_popstack(x);
	if(x->stacklen) {
		x->elem = (char *)x->stack+x->stacklen-1;
		while(*(x->elem-1))
			x->elem--;
		return YXML_ELEMEND;
	}
	x->elem = (char *)x->stack;
	x->state = YXMLS_misc3;
	return YXML_ELEMEND;
}

static inline yxml_ret_t yxml_elemclose(yxml_t *x, unsigned ch) {
	if(*((unsigned char *)x->elem) != ch)
		return YXML_ECLOSE;
	x->elem++;
	return YXML_OK;
}

static inline yxml_ret_t yxml_elemcloseend(yxml_t *x, unsigned ch) {
	if(*x->elem)
		return YXML_ECLOSE;
	return yxml_selfclose(x, ch);
}

static inline yxml_ret_t yxml_attrstart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->attr, ch); }
static inline yxml_ret_t yxml_attrname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
static inline yxml_ret_t yxml_attrnameend(yxml_t *x, unsigned ch) { return YXML_ATTRSTART; }
static inline yxml_ret_t yxml_attrvalend (yxml_t *x, unsigned ch) { yxml_popstack(x); return YXML_ATTREND; }

static inline yxml_ret_t yxml_pistart  (yxml_t *x, unsigned ch) { return yxml_pushstack(x, &x->pi, ch); }
static inline yxml_ret_t yxml_piname   (yxml_t *x, unsigned ch) { return yxml_pushstackc(x, ch); }
static inline yxml_ret_t yxml_piabort  (yxml_t *x, unsigned ch) { yxml_popstack(x); return YXML_OK; }
static inline yxml_ret_t yxml_pinameend(yxml_t *x, unsigned ch) {
	return (x->pi[0]|32) == 'x' && (x->pi[1]|32) == 'm' && (x->pi[2]|32) == 'l' && !x->pi[3] ? YXML_ESYN : YXML_PISTART;
}
static inline yxml_ret_t yxml_pivalend (yxml_t *x, unsigned ch) { yxml_popstack(x); x->pi = (char *)x->stack; return YXML_PIEND; }

static inline yxml_ret_t yxml_refstart(yxml_t *x, unsigned ch) {
	memset(x->data, 0, sizeof(x->data));
	x->reflen = 0;
	return YXML_OK;
}

static yxml_ret_t yxml_ref(yxml_t *x, unsigned ch) {
	if(x->reflen >= sizeof(x->data)-1)
		return YXML_EREF;
	yxml_setchar(x->data+x->reflen, ch);
	x->reflen++;
	return YXML_OK;
}

static yxml_ret_t yxml_refend(yxml_t *x, yxml_ret_t ret) {
	unsigned char *r = (unsigned char *)x->data;
	unsigned ch = 0;
	if(*r == '#') {
		if(r[1] == 'x')
			for(r += 2; yxml_isHex((unsigned)*r); r++)
				ch = (ch<<4) + (*r <= '9' ? *r-'0' : (*r|32)-'a' + 10);
		else
			for(r++; yxml_isNum((unsigned)*r); r++)
				ch = (ch*10) + (*r-'0');
		if(*r)
			ch = 0;
	} else {
		uint64_t i = INTFROM5CHARS(r[0], r[1], r[2], r[3], r[4]);
		ch =
			i == INTFROM5CHARS('l','t', 0,  0, 0) ? '<' :
			i == INTFROM5CHARS('g','t', 0,  0, 0) ? '>' :
			i == INTFROM5CHARS('a','m','p', 0, 0) ? '&' :
			i == INTFROM5CHARS('a','p','o','s',0) ? '\'':
			i == INTFROM5CHARS('q','u','o','t',0) ? '"' : 0;
	}

	/* Codepoints not allowed in the XML 1.1 definition of a Char */
	if(!ch || ch > 0x10FFFF || ch == 0xFFFE || ch == 0xFFFF || (ch-0xDFFF) < 0x7FF)
		return YXML_EREF;
	yxml_setutf8(x->data, ch);
	return ret;
}

static inline yxml_ret_t yxml_refcontent(yxml_t *x, unsigned ch) { return yxml_refend(x, YXML_CONTENT); }
static inline yxml_ret_t yxml_refattrval(yxml_t *x, unsigned ch) { return yxml_refend(x, YXML_ATTRVAL); }

void yxml_init(yxml_t *x, void *stack, size_t stacksize) {
	memset(x, 0, sizeof(*x));
	x->line = 1;
	x->stack = (unsigned char*)stack;
	x->stacksize = stacksize;
	*x->stack = 0;
	x->elem = x->pi = x->attr = (char *)x->stack;
	x->state = YXMLS_init;
}

yxml_ret_t yxml_parse(yxml_t *x, int _ch) {
	/* Ensure that characters are in the range of 0..255 rather than -126..125.
	 * All character comparisons are done with positive integers. */
	unsigned ch = (unsigned)(_ch+256) & 0xff;
	if(!ch)
		return YXML_ESYN;
	x->total++;

	/* End-of-Line normalization, "\rX", "\r\n" and "\n" are recognized and
	 * normalized to a single '\n' as per XML 1.0 section 2.11. XML 1.1 adds
	 * some non-ASCII character sequences to this list, but we can only handle
	 * ASCII here without making assumptions about the input encoding. */
	if(x->ignore == ch) {
		x->ignore = 0;
		return YXML_OK;
	}
	x->ignore = (ch == 0xd) * 0xa;
	if(ch == 0xa || ch == 0xd) {
		ch = 0xa;
		x->line++;
		x->byte = 0;
	}
	x->byte++;

	switch((yxml_state_t)x->state) {
	case YXMLS_string:
		if(ch == *x->string) {
			x->string++;
			if(!*x->string)
				x->state = x->nextstate;
			return YXML_OK;
		}
		break;
	case YXMLS_attr0:
		if(yxml_isName(ch))
			return yxml_attrname(x, ch);
		if(yxml_isSP(ch)) {
			x->state = YXMLS_attr1;
			return yxml_attrnameend(x, ch);
		}
		if(ch == (unsigned char)'=') {
			x->state = YXMLS_attr2;
			return yxml_attrnameend(x, ch);
		}
		break;
	case YXMLS_attr1:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'=') {
			x->state = YXMLS_attr2;
			return YXML_OK;
		}
		break;
	case YXMLS_attr2:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'\'' || ch == (unsigned char)'"') {
			x->state = YXMLS_attr3;
			x->quote = ch;
			return YXML_OK;
		}
		break;
	case YXMLS_attr3:
		if(yxml_isAttValue(ch))
			return yxml_dataattr(x, ch);
		if(ch == (unsigned char)'&') {
			x->state = YXMLS_attr4;
			return yxml_refstart(x, ch);
		}
		if(x->quote == ch) {
			x->state = YXMLS_elem2;
			return yxml_attrvalend(x, ch);
		}
		break;
	case YXMLS_attr4:
		if(yxml_isRef(ch))
			return yxml_ref(x, ch);
		if(ch == (unsigned char)'\x3b') {
			x->state = YXMLS_attr3;
			return yxml_refattrval(x, ch);
		}
		break;
	case YXMLS_cd0:
		if(ch == (unsigned char)']') {
			x->state = YXMLS_cd1;
			return YXML_OK;
		}
		if(yxml_isChar(ch))
			return yxml_datacontent(x, ch);
		break;
	case YXMLS_cd1:
		if(ch == (unsigned char)']') {
			x->state = YXMLS_cd2;
			return YXML_OK;
		}
		if(yxml_isChar(ch)) {
			x->state = YXMLS_cd0;
			return yxml_datacd1(x, ch);
		}
		break;
	case YXMLS_cd2:
		if(ch == (unsigned char)']')
			return yxml_datacontent(x, ch);
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc2;
			return YXML_OK;
		}
		if(yxml_isChar(ch)) {
			x->state = YXMLS_cd0;
			return yxml_datacd2(x, ch);
		}
		break;
	case YXMLS_comment0:
		if(ch == (unsigned char)'-') {
			x->state = YXMLS_comment1;
			return YXML_OK;
		}
		break;
	case YXMLS_comment1:
		if(ch == (unsigned char)'-') {
			x->state = YXMLS_comment2;
			return YXML_OK;
		}
		break;
	case YXMLS_comment2:
		if(ch == (unsigned char)'-') {
			x->state = YXMLS_comment3;
			return YXML_OK;
		}
		if(yxml_isChar(ch))
			return YXML_OK;
		break;
	case YXMLS_comment3:
		if(ch == (unsigned char)'-') {
			x->state = YXMLS_comment4;
			return YXML_OK;
		}
		if(yxml_isChar(ch)) {
			x->state = YXMLS_comment2;
			return YXML_OK;
		}
		break;
	case YXMLS_comment4:
		if(ch == (unsigned char)'>') {
			x->state = x->nextstate;
			return YXML_OK;
		}
		break;
	case YXMLS_dt0:
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc1;
			return YXML_OK;
		}
		if(ch == (unsigned char)'\'' || ch == (unsigned char)'"') {
			x->state = YXMLS_dt1;
			x->quote = ch;
			x->nextstate = YXMLS_dt0;
			return YXML_OK;
		}
		if(ch == (unsigned char)'<') {
			x->state = YXMLS_dt2;
			return YXML_OK;
		}
		if(yxml_isChar(ch))
			return YXML_OK;
		break;
	case YXMLS_dt1:
		if(x->quote == ch) {
			x->state = x->nextstate;
			return YXML_OK;
		}
		if(yxml_isChar(ch))
			return YXML_OK;
		break;
	case YXMLS_dt2:
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi0;
			x->nextstate = YXMLS_dt0;
			return YXML_OK;
		}
		if(ch == (unsigned char)'!') {
			x->state = YXMLS_dt3;
			return YXML_OK;
		}
		break;
	case YXMLS_dt3:
		if(ch == (unsigned char)'-') {
			x->state = YXMLS_comment1;
			x->nextstate = YXMLS_dt0;
			return YXML_OK;
		}
		if(yxml_isChar(ch)) {
			x->state = YXMLS_dt4;
			return YXML_OK;
		}
		break;
	case YXMLS_dt4:
		if(ch == (unsigned char)'\'' || ch == (unsigned char)'"') {
			x->state = YXMLS_dt1;
			x->quote = ch;
			x->nextstate = YXMLS_dt4;
			return YXML_OK;
		}
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_dt0;
			return YXML_OK;
		}
		if(yxml_isChar(ch))
			return YXML_OK;
		break;
	case YXMLS_elem0:
		if(yxml_isName(ch))
			return yxml_elemname(x, ch);
		if(yxml_isSP(ch)) {
			x->state = YXMLS_elem1;
			return yxml_elemnameend(x, ch);
		}
		if(ch == (unsigned char)'/') {
			x->state = YXMLS_elem3;
			return yxml_elemnameend(x, ch);
		}
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc2;
			return yxml_elemnameend(x, ch);
		}
		break;
	case YXMLS_elem1:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'/') {
			x->state = YXMLS_elem3;
			return YXML_OK;
		}
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc2;
			return YXML_OK;
		}
		if(yxml_isNameStart(ch)) {
			x->state = YXMLS_attr0;
			return yxml_attrstart(x, ch);
		}
		break;
	case YXMLS_elem2:
		if(yxml_isSP(ch)) {
			x->state = YXMLS_elem1;
			return YXML_OK;
		}
		if(ch == (unsigned char)'/') {
			x->state = YXMLS_elem3;
			return YXML_OK;
		}
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc2;
			return YXML_OK;
		}
		break;
	case YXMLS_elem3:
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc2;
			return yxml_selfclose(x, ch);
		}
		break;
	case YXMLS_enc0:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'=') {
			x->state = YXMLS_enc1;
			return YXML_OK;
		}
		break;
	case YXMLS_enc1:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'\'' || ch == (unsigned char)'"') {
			x->state = YXMLS_enc2;
			x->quote = ch;
			return YXML_OK;
		}
		break;
	case YXMLS_enc2:
		if(yxml_isAlpha(ch)) {
			x->state = YXMLS_enc3;
			return YXML_OK;
		}
		break;
	case YXMLS_enc3:
		if(yxml_isEncName(ch))
			return YXML_OK;
		if(x->quote == ch) {
			x->state = YXMLS_xmldecl6;
			return YXML_OK;
		}
		break;
	case YXMLS_etag0:
		if(yxml_isNameStart(ch)) {
			x->state = YXMLS_etag1;
			return yxml_elemclose(x, ch);
		}
		break;
	case YXMLS_etag1:
		if(yxml_isName(ch))
			return yxml_elemclose(x, ch);
		if(yxml_isSP(ch)) {
			x->state = YXMLS_etag2;
			return yxml_elemcloseend(x, ch);
		}
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc2;
			return yxml_elemcloseend(x, ch);
		}
		break;
	case YXMLS_etag2:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc2;
			return YXML_OK;
		}
		break;
	case YXMLS_init:
		if(ch == (unsigned char)'\xef') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_misc0;
			x->string = (unsigned char *)"\xbb\xbf";
			return YXML_OK;
		}
		if(yxml_isSP(ch)) {
			x->state = YXMLS_misc0;
			return YXML_OK;
		}
		if(ch == (unsigned char)'<') {
			x->state = YXMLS_le0;
			return YXML_OK;
		}
		break;
	case YXMLS_le0:
		if(ch == (unsigned char)'!') {
			x->state = YXMLS_lee1;
			return YXML_OK;
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_leq0;
			return YXML_OK;
		}
		if(yxml_isNameStart(ch)) {
			x->state = YXMLS_elem0;
			return yxml_elemstart(x, ch);
		}
		break;
	case YXMLS_le1:
		if(ch == (unsigned char)'!') {
			x->state = YXMLS_lee1;
			return YXML_OK;
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi0;
			x->nextstate = YXMLS_misc1;
			return YXML_OK;
		}
		if(yxml_isNameStart(ch)) {
			x->state = YXMLS_elem0;
			return yxml_elemstart(x, ch);
		}
		break;
	case YXMLS_le2:
		if(ch == (unsigned char)'!') {
			x->state = YXMLS_lee2;
			return YXML_OK;
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi0;
			x->nextstate = YXMLS_misc2;
			return YXML_OK;
		}
		if(ch == (unsigned char)'/') {
			x->state = YXMLS_etag0;
			return YXML_OK;
		}
		if(yxml_isNameStart(ch)) {
			x->state = YXMLS_elem0;
			return yxml_elemstart(x, ch);
		}
		break;
	case YXMLS_le3:
		if(ch == (unsigned char)'!') {
			x->state = YXMLS_comment0;
			x->nextstate = YXMLS_misc3;
			return YXML_OK;
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi0;
			x->nextstate = YXMLS_misc3;
			return YXML_OK;
		}
		break;
	case YXMLS_lee1:
		if(ch == (unsigned char)'-') {
			x->state = YXMLS_comment1;
			x->nextstate = YXMLS_misc1;
			return YXML_OK;
		}
		if(ch == (unsigned char)'D') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_dt0;
			x->string = (unsigned char *)"OCTYPE";
			return YXML_OK;
		}
		break;
	case YXMLS_lee2:
		if(ch == (unsigned char)'-') {
			x->state = YXMLS_comment1;
			x->nextstate = YXMLS_misc2;
			return YXML_OK;
		}
		if(ch == (unsigned char)'[') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_cd0;
			x->string = (unsigned char *)"CDATA[";
			return YXML_OK;
		}
		break;
	case YXMLS_leq0:
		if(ch == (unsigned char)'x') {
			x->state = YXMLS_xmldecl0;
			x->nextstate = YXMLS_misc1;
			return yxml_pistart(x, ch);
		}
		if(yxml_isNameStart(ch)) {
			x->state = YXMLS_pi1;
			x->nextstate = YXMLS_misc1;
			return yxml_pistart(x, ch);
		}
		break;
	case YXMLS_misc0:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'<') {
			x->state = YXMLS_le0;
			return YXML_OK;
		}
		break;
	case YXMLS_misc1:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'<') {
			x->state = YXMLS_le1;
			return YXML_OK;
		}
		break;
	case YXMLS_misc2:
		if(ch == (unsigned char)'<') {
			x->state = YXMLS_le2;
			return YXML_OK;
		}
		if(ch == (unsigned char)'&') {
			x->state = YXMLS_misc2a;
			return yxml_refstart(x, ch);
		}
		if(yxml_isChar(ch))
			return yxml_datacontent(x, ch);
		break;
	case YXMLS_misc2a:
		if(yxml_isRef(ch))
			return yxml_ref(x, ch);
		if(ch == (unsigned char)'\x3b') {
			x->state = YXMLS_misc2;
			return yxml_refcontent(x, ch);
		}
		break;
	case YXMLS_misc3:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'<') {
			x->state = YXMLS_le3;
			return YXML_OK;
		}
		break;
	case YXMLS_pi0:
		if(yxml_isNameStart(ch)) {
			x->state = YXMLS_pi1;
			return yxml_pistart(x, ch);
		}
		break;
	case YXMLS_pi1:
		if(yxml_isName(ch))
			return yxml_piname(x, ch);
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi4;
			return yxml_pinameend(x, ch);
		}
		if(yxml_isSP(ch)) {
			x->state = YXMLS_pi2;
			return yxml_pinameend(x, ch);
		}
		break;
	case YXMLS_pi2:
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi3;
			return YXML_OK;
		}
		if(yxml_isChar(ch))
			return yxml_datapi1(x, ch);
		break;
	case YXMLS_pi3:
		if(ch == (unsigned char)'>') {
			x->state = x->nextstate;
			return yxml_pivalend(x, ch);
		}
		if(yxml_isChar(ch)) {
			x->state = YXMLS_pi2;
			return yxml_datapi2(x, ch);
		}
		break;
	case YXMLS_pi4:
		if(ch == (unsigned char)'>') {
			x->state = x->nextstate;
			return yxml_pivalend(x, ch);
		}
		break;
	case YXMLS_std0:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'=') {
			x->state = YXMLS_std1;
			return YXML_OK;
		}
		break;
	case YXMLS_std1:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'\'' || ch == (unsigned char)'"') {
			x->state = YXMLS_std2;
			x->quote = ch;
			return YXML_OK;
		}
		break;
	case YXMLS_std2:
		if(ch == (unsigned char)'y') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_std3;
			x->string = (unsigned char *)"es";
			return YXML_OK;
		}
		if(ch == (unsigned char)'n') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_std3;
			x->string = (unsigned char *)"o";
			return YXML_OK;
		}
		break;
	case YXMLS_std3:
		if(x->quote == ch) {
			x->state = YXMLS_xmldecl8;
			return YXML_OK;
		}
		break;
	case YXMLS_ver0:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'=') {
			x->state = YXMLS_ver1;
			return YXML_OK;
		}
		break;
	case YXMLS_ver1:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'\'' || ch == (unsigned char)'"') {
			x->state = YXMLS_string;
			x->quote = ch;
			x->nextstate = YXMLS_ver2;
			x->string = (unsigned char *)"1.";
			return YXML_OK;
		}
		break;
	case YXMLS_ver2:
		if(yxml_isNum(ch)) {
			x->state = YXMLS_ver3;
			return YXML_OK;
		}
		break;
	case YXMLS_ver3:
		if(yxml_isNum(ch))
			return YXML_OK;
		if(x->quote == ch) {
			x->state = YXMLS_xmldecl4;
			return YXML_OK;
		}
		break;
	case YXMLS_xmldecl0:
		if(ch == (unsigned char)'m') {
			x->state = YXMLS_xmldecl1;
			return yxml_piname(x, ch);
		}
		if(yxml_isName(ch)) {
			x->state = YXMLS_pi1;
			return yxml_piname(x, ch);
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi4;
			return yxml_pinameend(x, ch);
		}
		if(yxml_isSP(ch)) {
			x->state = YXMLS_pi2;
			return yxml_pinameend(x, ch);
		}
		break;
	case YXMLS_xmldecl1:
		if(ch == (unsigned char)'l') {
			x->state = YXMLS_xmldecl2;
			return yxml_piname(x, ch);
		}
		if(yxml_isName(ch)) {
			x->state = YXMLS_pi1;
			return yxml_piname(x, ch);
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_pi4;
			return yxml_pinameend(x, ch);
		}
		if(yxml_isSP(ch)) {
			x->state = YXMLS_pi2;
			return yxml_pinameend(x, ch);
		}
		break;
	case YXMLS_xmldecl2:
		if(yxml_isSP(ch)) {
			x->state = YXMLS_xmldecl3;
			return yxml_piabort(x, ch);
		}
		if(yxml_isName(ch)) {
			x->state = YXMLS_pi1;
			return yxml_piname(x, ch);
		}
		break;
	case YXMLS_xmldecl3:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'v') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_ver0;
			x->string = (unsigned char *)"ersion";
			return YXML_OK;
		}
		break;
	case YXMLS_xmldecl4:
		if(yxml_isSP(ch)) {
			x->state = YXMLS_xmldecl5;
			return YXML_OK;
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_xmldecl9;
			return YXML_OK;
		}
		break;
	case YXMLS_xmldecl5:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_xmldecl9;
			return YXML_OK;
		}
		if(ch == (unsigned char)'e') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_enc0;
			x->string = (unsigned char *)"ncoding";
			return YXML_OK;
		}
		if(ch == (unsigned char)'s') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_std0;
			x->string = (unsigned char *)"tandalone";
			return YXML_OK;
		}
		break;
	case YXMLS_xmldecl6:
		if(yxml_isSP(ch)) {
			x->state = YXMLS_xmldecl7;
			return YXML_OK;
		}
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_xmldecl9;
			return YXML_OK;
		}
		break;
	case YXMLS_xmldecl7:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_xmldecl9;
			return YXML_OK;
		}
		if(ch == (unsigned char)'s') {
			x->state = YXMLS_string;
			x->nextstate = YXMLS_std0;
			x->string = (unsigned char *)"tandalone";
			return YXML_OK;
		}
		break;
	case YXMLS_xmldecl8:
		if(yxml_isSP(ch))
			return YXML_OK;
		if(ch == (unsigned char)'?') {
			x->state = YXMLS_xmldecl9;
			return YXML_OK;
		}
		break;
	case YXMLS_xmldecl9:
		if(ch == (unsigned char)'>') {
			x->state = YXMLS_misc1;
			return YXML_OK;
		}
		break;
	}
	return YXML_ESYN;
}

yxml_ret_t yxml_eof(yxml_t *x) {
	if(x->state != YXMLS_misc3)
		return YXML_EEOF;
	return YXML_OK;
}


/**** amalgamated original file "/src/ua_types_encoding_xml.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */



#include <float.h>
#include <math.h>


/* Replicate yxml_isNameStart and yxml_isName from yxml. But differently we
 * already break at the first colon, so "uax:String" becomes "String". */
static UA_String
backtrackName(const char *xml, unsigned end) {
    unsigned pos = end;
    for(; pos > 0; pos--) {
        unsigned char c = (unsigned char)xml[pos-1];
        if(c >= 'a' && c <= 'z') continue; /* isAlpha */
        if(c >= 'A' && c <= 'Z') continue; /* isAlpha */
        if(c >= '0' && c <= '9') continue; /* isNum */
        if(c == '_' || c >= 128 || c == '-'|| c == '.') continue;
        break;
    }
    UA_String s = {end - pos, (UA_Byte*)(uintptr_t)xml + pos};
    return s;
}

xml_result
xml_tokenize(const char *xml, unsigned int len,
             xml_token *tokens, unsigned int max_tokens) {
    xml_result res;
    memset(&res, 0, sizeof(xml_result));
    res.tokens = tokens;

    yxml_t ctx;
    char buf[512];
    yxml_init(&ctx, buf, 512);

    unsigned char top = 0;
    unsigned tokenPos = 0;
    xml_token *stack[32]; /* Max nesting depth is 32 */
    xml_token backup_tokens[32]; /* To be used when the tokens run out */

    /* Help clang-analyzer */
#ifdef __clang_analyzer__
    memset(stack, 0, 32 * sizeof(void*));
    memset(backup_tokens, 0, 32 * sizeof(xml_token));
#endif

    stack[top] = &backup_tokens[top];
    memset(stack[top], 0, sizeof(xml_token));

    unsigned val_begin = 0;
    unsigned pos = 0;
    for(; pos < len; pos++) {
#ifdef __clang_analyzer__
        UA_assert(stack[top] != NULL);
#endif
        yxml_ret_t xml_status = yxml_parse(&ctx, xml[pos]);
        switch(xml_status) {
        case YXML_EEOF:
        case YXML_EREF:
        case YXML_ECLOSE:
        case YXML_ESTACK:
        case YXML_ESYN:
        default:
            goto errout;
        case YXML_OK:
            continue;
        case YXML_ELEMSTART:
        case YXML_ATTRSTART: {
            if(xml_status == YXML_ELEMSTART) {
                stack[top]->children++;
                stack[top]->content = UA_STRING_NULL; /* Only the leaf elements have content */
            } else {
                stack[top]->attributes++;
            }
            top++;
            if(top >= 32)
                goto errout; /* nesting too deep */
            stack[top] = (tokenPos < max_tokens) ? &tokens[tokenPos] : &backup_tokens[top];
            memset(stack[top], 0, sizeof(xml_token));
            stack[top]->type = (xml_status == YXML_ELEMSTART) ? XML_TOKEN_ELEMENT : XML_TOKEN_ATTRIBUTE;
            stack[top]->name = backtrackName(xml, pos);
            const char *start = xml + pos;
            if(xml_status == YXML_ELEMSTART) {
                while(*start != '<')
                    start--;
            }
            stack[top]->start = (unsigned)(start - xml);
            tokenPos++;
            val_begin = 0; /* if the previous non-leaf element started to collect content */
            break;
        }
        case YXML_CONTENT:
        case YXML_ATTRVAL:
            if(val_begin == 0)
                val_begin = pos;
            stack[top]->end = pos;
            break;
        case YXML_ELEMEND:
        case YXML_ATTREND:
            if(top == 0)
                goto errout; /* more closes than opens */
            if(val_begin > 0) {
                stack[top]->content.data = (UA_Byte*)(uintptr_t)xml + val_begin;
                stack[top]->content.length = stack[top]->end + 1 - val_begin;
            }
            stack[top]->end = pos;
            if(xml_status == YXML_ELEMEND) {
                /* Saw "</", looking for the closing ">" */
                while(stack[top]->end < len && xml[stack[top]->end] != '>')
                    stack[top]->end++;
                stack[top]->end++;
                if(stack[top]->end > len)
                    goto errout;
            }
            val_begin = 0;
            top--;
            break;
        case YXML_PISTART:
        case YXML_PICONTENT:
        case YXML_PIEND:
            continue; /* Ignore processing instructions */
        }
    }

    /* Check that all elements were closed */
    if(yxml_eof(&ctx) != YXML_OK)
        goto errout;

    res.num_tokens = tokenPos;
    if(tokenPos > max_tokens)
        res.error = XML_ERROR_OVERFLOW;
    return res;

 errout:
    res.error_pos = pos;
    res.error = XML_ERROR_INVALID;
    return res;
}

/* Map for decoding a XML complex object type. An array of this is passed to the
 * decodeXmlFields function. If the xml element with name "fieldName" is found
 * in the xml complex object (mark as found) decode the value with the "function"
 * and write result into "fieldPointer" (destination). */
typedef struct {
    UA_String name;
    void *fieldPointer;
    decodeXmlSignature function;
    UA_Boolean found;
    const UA_DataType *type; /* Must be set for values that can be "null". If
                              * the function is not set, decode via the
                              * type->typeKind. */
} XmlDecodeEntry;

/* Elements for XML complex types */
#define UA_XML_GUID_STRING "String"
#define UA_XML_NODEID_IDENTIFIER "Identifier"
#define UA_XML_EXPANDEDNODEID_IDENTIFIER "Identifier"
#define UA_XML_STATUSCODE_CODE "Code"
#define UA_XML_QUALIFIEDNAME_NAMESPACEINDEX "NamespaceIndex"
#define UA_XML_QUALIFIEDNAME_NAME "Name"
#define UA_XML_LOCALIZEDTEXT_LOCALE "Locale"
#define UA_XML_LOCALIZEDTEXT_TEXT "Text"
#define UA_XML_EXTENSIONOBJECT_TYPEID "TypeId"
#define UA_XML_EXTENSIONOBJECT_BODY "Body"
#define UA_XML_EXTENSIONOBJECT_BYTESTRING "ByteString"
#define UA_XML_VARIANT_VALUE "Value"

/************/
/* Encoding */
/************/

#define ENCODE_XML(TYPE) static status \
    TYPE##_encodeXml(CtxXml *ctx, const UA_##TYPE *src, const UA_DataType *type)

#define ENCODE_DIRECT_XML(SRC, TYPE) \
    TYPE##_encodeXml(ctx, (const UA_##TYPE*)SRC, NULL)

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
xmlEncodeWriteChars(CtxXml *ctx, const char *c, size_t len) {
    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly && len)
        memcpy(ctx->pos, c, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeXmlElemNameBegin(CtxXml *ctx, const char* name) {
    if(ctx->depth >= UA_XML_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    status ret = UA_STATUSCODE_GOOD;
    ret |= xmlEncodeWriteChars(ctx, "<", 1);
    ret |= xmlEncodeWriteChars(ctx, name, strlen(name));
    ret |= xmlEncodeWriteChars(ctx, ">", 1);
    ctx->depth++;
    return ret;
}

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeXmlElemNameEnd(CtxXml *ctx, const char* name) {
    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth--;
    status ret = UA_STATUSCODE_GOOD;
    ret |= xmlEncodeWriteChars(ctx, "</", 2);
    ret |= xmlEncodeWriteChars(ctx, name, strlen(name));
    ret |= xmlEncodeWriteChars(ctx, ">", 1);
    return ret;
}

static status UA_INTERNAL_FUNC_ATTR_WARN_UNUSED_RESULT
writeXmlElement(CtxXml *ctx, const char *name,
                const void *value, const UA_DataType *type) {
    status ret = UA_STATUSCODE_GOOD;
    ret |= writeXmlElemNameBegin(ctx, name);
    ret |= encodeXmlJumpTable[type->typeKind](ctx, value, type);
    ret |= writeXmlElemNameEnd(ctx, name);
    return ret;
}

/* Boolean */
ENCODE_XML(Boolean) {
    if(*src == true)
        return xmlEncodeWriteChars(ctx, "true", 4);
    return xmlEncodeWriteChars(ctx, "false", 5);
}

static status encodeSigned(CtxXml *ctx, UA_Int64 value, char* buffer) {
    UA_UInt16 digits = itoaSigned(value, buffer);
    return xmlEncodeWriteChars(ctx, buffer, digits);
}

static status encodeUnsigned(CtxXml *ctx, UA_UInt64 value, char* buffer) {
    UA_UInt16 digits = itoaUnsigned(value, buffer, 10);
    return xmlEncodeWriteChars(ctx, buffer, digits);
}

/* signed Byte */
ENCODE_XML(SByte) {
    char buf[5];
    return encodeSigned(ctx, *src, buf);
}

/* Byte */
ENCODE_XML(Byte) {
    char buf[4];
    return encodeUnsigned(ctx, *src, buf);
}

/* Int16 */
ENCODE_XML(Int16) {
    char buf[7];
    return encodeSigned(ctx, *src, buf);
}

/* UInt16 */
ENCODE_XML(UInt16) {
    char buf[6];
    return encodeUnsigned(ctx, *src, buf);
}

/* Int32 */
ENCODE_XML(Int32) {
    char buf[12];
    return encodeSigned(ctx, *src, buf);
}

/* UInt32 */
ENCODE_XML(UInt32) {
    char buf[11];
    return encodeUnsigned(ctx, *src, buf);
}

/* Int64 */
ENCODE_XML(Int64) {
    char buf[23];
    return encodeSigned(ctx, *src, buf);
}

/* UInt64 */
ENCODE_XML(UInt64) {
    char buf[23];
    return encodeUnsigned(ctx, *src, buf);
}

/* Float */
ENCODE_XML(Float) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "NaN");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "INF");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "-INF");
        len = strlen(buffer);
    } else {
        len = dtoa((UA_Double)*src, buffer);
    }
    return xmlEncodeWriteChars(ctx, buffer, len);
}

/* Double */
ENCODE_XML(Double) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "NaN");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "INF");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "-INF");
        len = strlen(buffer);
    } else {
        len = dtoa(*src, buffer);
    }
    return xmlEncodeWriteChars(ctx, buffer, len);
}

/* String */
ENCODE_XML(String) {
    return xmlEncodeWriteChars(ctx, (const char*)src->data, src->length);
}

/* Guid */
ENCODE_XML(Guid) {
    UA_Byte buf[36];
    UA_ByteString hexBuf = {36, buf};
    UA_Guid_to_hex(src, hexBuf.data, false);
    return writeXmlElement(ctx, UA_XML_GUID_STRING, &hexBuf,
                           &UA_TYPES[UA_TYPES_STRING]);
}

/* DateTime */
ENCODE_XML(DateTime) {
    UA_Byte buffer[40];
    UA_String str = {40, buffer};
    encodeDateTime(*src, &str);
    return xmlEncodeWriteChars(ctx, (const char*)str.data, str.length);
}

/* ByteString */
ENCODE_XML(ByteString) {
    if(!src->data)
        return xmlEncodeWriteChars(ctx, "null", 4);

    if(src->length == 0)
        return UA_STATUSCODE_GOOD;

    size_t flen = 0;
    unsigned char *ba64 = UA_base64(src->data, src->length, &flen);

    /* Not converted, no mem */
    if(!ba64)
        return UA_STATUSCODE_BADENCODINGERROR;

    if(ctx->pos + flen > ctx->end) {
        UA_free(ba64);
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    }

    /* Copy flen bytes to output stream. */
    if(!ctx->calcOnly)
        memcpy(ctx->pos, ba64, flen);
    ctx->pos += flen;

    /* Base64 result no longer needed */
    UA_free(ba64);

    return UA_STATUSCODE_GOOD;
}

/* NodeId */
ENCODE_XML(NodeId) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_String out = UA_STRING_NULL;
    ret |= UA_NodeId_printEx(src, &out, ctx->namespaceMapping);
    ret |= writeXmlElement(ctx, UA_XML_NODEID_IDENTIFIER,
                           &out, &UA_TYPES[UA_TYPES_STRING]);
    UA_String_clear(&out);
    return ret;
}

/* ExpandedNodeId */
ENCODE_XML(ExpandedNodeId) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_String out = UA_STRING_NULL;
    ret |= UA_ExpandedNodeId_printEx(src, &out,
                                     ctx->namespaceMapping,
                                     ctx->serverUrisSize,
                                     ctx->serverUris);
    ret |= writeXmlElement(ctx, UA_XML_EXPANDEDNODEID_IDENTIFIER,
                           &out, &UA_TYPES[UA_TYPES_STRING]);
    UA_String_clear(&out);
    return ret;
}

/* StatusCode */
ENCODE_XML(StatusCode) {
    return writeXmlElement(ctx, UA_XML_STATUSCODE_CODE,
                           src, &UA_TYPES[UA_TYPES_UINT32]);
}

/* QualifiedName */
ENCODE_XML(QualifiedName) {
    /* Map the NamespaceIndex */
    UA_UInt16 index = src->namespaceIndex;
    if(ctx->namespaceMapping)
        index = UA_NamespaceMapping_local2Remote(ctx->namespaceMapping, index);

    /* Write out the elements */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    ret |= writeXmlElement(ctx, UA_XML_QUALIFIEDNAME_NAMESPACEINDEX,
                           &index, &UA_TYPES[UA_TYPES_UINT16]);
    ret |= writeXmlElement(ctx, UA_XML_QUALIFIEDNAME_NAME,
                           &src->name, &UA_TYPES[UA_TYPES_STRING]);
    return ret;
}

/* LocalizedText */
ENCODE_XML(LocalizedText) {
    return writeXmlElement(ctx, UA_XML_LOCALIZEDTEXT_LOCALE,
                           &src->locale, &UA_TYPES[UA_TYPES_STRING]) |
        writeXmlElement(ctx, UA_XML_LOCALIZEDTEXT_TEXT,
                        &src->text, &UA_TYPES[UA_TYPES_STRING]);
}

/* ExtensionObject */
ENCODE_XML(ExtensionObject) {
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return UA_STATUSCODE_GOOD;

    /* The body of the ExtensionObject contains a single element
     * which is either a ByteString or XML encoded Structure:
     * https://reference.opcfoundation.org/Core/Part6/v104/docs/5.3.1.16. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING ||
       src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML) {
        /* Write the type NodeId */
        ret = writeXmlElement(ctx, UA_XML_EXTENSIONOBJECT_TYPEID,
                              &src->content.encoded.typeId,
                              &UA_TYPES[UA_TYPES_NODEID]);

        /* Write the body */
        ret |= writeXmlElemNameBegin(ctx, UA_XML_EXTENSIONOBJECT_BODY);
        if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING)
           ret |= writeXmlElement(ctx, "ByteString", &src->content.encoded.body,
                                  &UA_TYPES[UA_TYPES_BYTESTRING]);
        else
            ret |= ENCODE_DIRECT_XML(&src->content.encoded.body, String);
        ret |= writeXmlElemNameEnd(ctx, UA_XML_EXTENSIONOBJECT_BODY);
    } else {
        /* Write the decoded value */
        const UA_DataType *decoded_type = src->content.decoded.type;

        /* Write the type NodeId */
        ret = writeXmlElement(ctx, UA_XML_EXTENSIONOBJECT_TYPEID,
                              &decoded_type->typeId, &UA_TYPES[UA_TYPES_NODEID]);

        /* Write the body */
        ret |= writeXmlElemNameBegin(ctx, UA_XML_EXTENSIONOBJECT_BODY);
        ret |= writeXmlElement(ctx, decoded_type->typeName, src->content.decoded.data, decoded_type);
        ret |= writeXmlElemNameEnd(ctx, UA_XML_EXTENSIONOBJECT_BODY);
    }

    return ret;
}

static status
Array_encodeXml(CtxXml *ctx, const void *ptr, size_t length,
                const UA_DataType *type) {
    char arrName[128];
    UA_ExtensionObject eo;

    UA_Boolean wrapEO = (type->typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(wrapEO) {
        UA_ExtensionObject_setValue(&eo, (void*)(uintptr_t)ptr, type);
        type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
    }

    size_t arrNameLen = strlen("ListOf") + strlen(type->typeName);
    if(arrNameLen >= 128)
        return UA_STATUSCODE_BADENCODINGERROR;
    memcpy(arrName, "ListOf", strlen("ListOf"));
    memcpy(arrName + strlen("ListOf"), type->typeName, strlen(type->typeName));
    arrName[arrNameLen] = '\0';

    uintptr_t uptr = (uintptr_t)ptr;
    status ret = writeXmlElemNameBegin(ctx, arrName);
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) {
        if(!wrapEO) {
            ret |= writeXmlElement(ctx, type->typeName, (const void*)uptr, type);
        } else {
            eo.content.decoded.data = (void*)uptr;
            ret |= writeXmlElement(ctx, type->typeName, &eo, type);
        }
        uptr += type->memSize;
    }
    ret |= writeXmlElemNameEnd(ctx, arrName);
    return ret;
}

ENCODE_XML(Variant) {
    if(!src->type)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Set the array type in the encoding mask */
    const bool isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL;

    if(src->arrayDimensionsSize > 1)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    ret |= writeXmlElemNameBegin(ctx, UA_XML_VARIANT_VALUE);
    if(!isArray) {
        const UA_DataType *srctype = src->type;
        void *ptr = src->data;
        UA_ExtensionObject eo;
        if(srctype->typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO) {
            /* Wrap value in an ExtensionObject */
            UA_ExtensionObject_setValue(&eo, (void*)(uintptr_t)ptr, srctype);
            ptr = &eo;
            srctype = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
        }
        ret |= writeXmlElement(ctx, srctype->typeName, ptr, srctype);
    } else {
        ret |= Array_encodeXml(ctx, src->data, src->arrayLength, src->type);
    }
    ret |= writeXmlElemNameEnd(ctx, UA_XML_VARIANT_VALUE);
    return ret;
}

static status
encodeXmlNotImplemented(CtxXml *ctx, const void *src, const UA_DataType *type) {
    (void)ctx, (void)src, (void)type;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const encodeXmlSignature encodeXmlJumpTable[UA_DATATYPEKINDS] = {
    (encodeXmlSignature)Boolean_encodeXml,          /* Boolean */
    (encodeXmlSignature)SByte_encodeXml,            /* SByte */
    (encodeXmlSignature)Byte_encodeXml,             /* Byte */
    (encodeXmlSignature)Int16_encodeXml,            /* Int16 */
    (encodeXmlSignature)UInt16_encodeXml,           /* UInt16 */
    (encodeXmlSignature)Int32_encodeXml,            /* Int32 */
    (encodeXmlSignature)UInt32_encodeXml,           /* UInt32 */
    (encodeXmlSignature)Int64_encodeXml,            /* Int64 */
    (encodeXmlSignature)UInt64_encodeXml,           /* UInt64 */
    (encodeXmlSignature)Float_encodeXml,            /* Float */
    (encodeXmlSignature)Double_encodeXml,           /* Double */
    (encodeXmlSignature)String_encodeXml,           /* String */
    (encodeXmlSignature)DateTime_encodeXml,         /* DateTime */
    (encodeXmlSignature)Guid_encodeXml,             /* Guid */
    (encodeXmlSignature)ByteString_encodeXml,       /* ByteString */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* XmlElement */
    (encodeXmlSignature)NodeId_encodeXml,           /* NodeId */
    (encodeXmlSignature)ExpandedNodeId_encodeXml,   /* ExpandedNodeId */
    (encodeXmlSignature)StatusCode_encodeXml,       /* StatusCode */
    (encodeXmlSignature)QualifiedName_encodeXml,    /* QualifiedName */
    (encodeXmlSignature)LocalizedText_encodeXml,    /* LocalizedText */
    (encodeXmlSignature)ExtensionObject_encodeXml,  /* ExtensionObject */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* DataValue */
    (encodeXmlSignature)Variant_encodeXml,          /* Variant */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* DiagnosticInfo */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* Decimal */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* Enum */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* Structure */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* Structure with optional fields */
    (encodeXmlSignature)encodeXmlNotImplemented,    /* Union */
    (encodeXmlSignature)encodeXmlNotImplemented     /* BitfieldCluster */
};

UA_StatusCode
UA_encodeXml(const void *src, const UA_DataType *type, UA_ByteString *outBuf,
             const UA_EncodeXmlOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate buffer */
    UA_Boolean allocated = false;
    status res = UA_STATUSCODE_GOOD;
    if(outBuf->length == 0) {
        size_t len = UA_calcSizeXml(src, type, options);
        res = UA_ByteString_allocBuffer(outBuf, len);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        allocated = true;
    }

    /* Set up the context */
    CtxXml ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = outBuf->data;
    ctx.end = &outBuf->data[outBuf->length];
    ctx.depth = 0;
    ctx.calcOnly = false;
    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
    }

    /* Encode */
    res = writeXmlElement(&ctx, type->typeName, src, type);

    /* Clean up */
    if(res == UA_STATUSCODE_GOOD)
        outBuf->length = (size_t)((uintptr_t)ctx.pos - (uintptr_t)outBuf->data);
    else if(allocated)
        UA_ByteString_clear(outBuf);

    return res;
}

/************/
/* CalcSize */
/************/

size_t
UA_calcSizeXml(const void *src, const UA_DataType *type,
               const UA_EncodeXmlOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Set up the context */
    CtxXml ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = NULL;
    ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
    ctx.depth = 0;
    if(options) {
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
    }

    ctx.calcOnly = true;

    /* Encode */
    status ret = writeXmlElement(&ctx, type->typeName, src, type);
    if(ret != UA_STATUSCODE_GOOD)
        return 0;
    return (size_t)ctx.pos;
}

/**********/
/* Decode */
/**********/

#define DECODE_XML(TYPE) static status                  \
    TYPE##_decodeXml(ParseCtxXml *ctx, UA_##TYPE *dst, const UA_DataType *type)

#define CHECK_DATA_BOUNDS                           \
    if(ctx->index >= ctx->tokensSize)               \
        return UA_STATUSCODE_BADDECODINGERROR;      \
    do { } while(0)

#define GET_ELEM_CONTENT                                           \
    const UA_Byte *data = ctx->tokens[ctx->index].content.data;    \
    size_t length = ctx->tokens[ctx->index].content.length;        \
    do {} while(0)

static void
skipXmlObject(ParseCtxXml *ctx) {
    size_t end_parent = ctx->tokens[ctx->index].end;
    while(ctx->index < ctx->tokensSize &&
          ctx->tokens[ctx->index].end <= end_parent) {
        ctx->index++;
    }
}

DECODE_XML(Boolean) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    if(length == 4 &&
       data[0] == 't' && data[1] == 'r' &&
       data[2] == 'u' && data[3] == 'e') {
        *dst = true;
    } else if(length == 5 &&
              data[0] == 'f' && data[1] == 'a' &&
              data[2] == 'l' && data[3] == 's' &&
              data[4] == 'e') {
        *dst = false;
    } else {
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
decodeSigned(const UA_Byte *data, size_t dataSize, UA_Int64 *dst) {
    if(!data || dataSize == 0)
        return UA_STATUSCODE_BADDECODINGERROR;
    size_t len = parseInt64((const char*)data, dataSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the XML section */
    for(size_t i = len; i < dataSize; i++) {
        if(data[i] != ' ' && data[i] - '\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
decodeUnsigned(const UA_Byte *data, size_t dataSize, UA_UInt64 *dst) {
    if(!data || dataSize == 0)
        return UA_STATUSCODE_BADDECODINGERROR;
    size_t len = parseUInt64((const char*)data, dataSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the XML section */
    for(size_t i = len; i < dataSize; i++) {
        if(data[i] != ' ' && data[i] - '\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

DECODE_XML(SByte) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_Int64 out = 0;
    UA_StatusCode s = decodeSigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_SBYTE_MIN || out > UA_SBYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_SByte)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(Byte) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_UInt64 out = 0;
    UA_StatusCode s = decodeUnsigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_BYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_Byte)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(Int16) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_Int64 out = 0;
    UA_StatusCode s = decodeSigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT16_MIN || out > UA_INT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_Int16)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(UInt16) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_UInt64 out = 0;
    UA_StatusCode s = decodeUnsigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_UInt16)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(Int32) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_Int64 out = 0;
    UA_StatusCode s = decodeSigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT32_MIN || out > UA_INT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_Int32)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(UInt32) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_UInt64 out = 0;
    UA_StatusCode s = decodeUnsigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_UInt32)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(Int64) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_Int64 out = 0;
    UA_StatusCode s = decodeSigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_Int64)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(UInt64) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    UA_UInt64 out = 0;
    UA_StatusCode s = decodeUnsigned(data, length, &out);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = (UA_UInt64)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(Double) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    if(!data || length == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/
     * Maximum digit counts for select IEEE floating-point formats: 1074
     * Sanity check. */
    if(length > 1075)
        return UA_STATUSCODE_BADDECODINGERROR;

    if(length == 3 && memcmp(data, "INF", 3) == 0) {
        *dst = INFINITY;
        return UA_STATUSCODE_GOOD;
    }

    if(length == 4 && memcmp(data, "-INF", 4) == 0) {
        *dst = -INFINITY;
        return UA_STATUSCODE_GOOD;
    }

    if(length == 3 && memcmp(data, "NaN", 3) == 0) {
        *dst = NAN;
        return UA_STATUSCODE_GOOD;
    }

    if(length == 3 && memcmp(data, "-NaN", 3) == 0) {
        *dst = NAN;
        return UA_STATUSCODE_GOOD;
    }

    size_t len = parseDouble((const char*)data, length, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < length; i++) {
        if(data[i] != ' ' && data[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

DECODE_XML(Float) {
    UA_Double v = 0.0;
    UA_StatusCode res = Double_decodeXml(ctx, &v, NULL);
    *dst = (UA_Float)v;
    return res;
}

DECODE_XML(String) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    /* Empty string? */
    if(length == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
        return UA_STATUSCODE_GOOD;
    }

    UA_String str = {length, (UA_Byte*)(uintptr_t)data};
    return UA_String_copy(&str, dst);
}

DECODE_XML(DateTime) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);
    UA_String str = {length, (UA_Byte*)(uintptr_t)data};
    return UA_DateTime_parse(dst, str);
}

/* Find the child with the given name and return its content.
 * This does not allocate/copy the content again. */
static status
getChildContent(ParseCtxXml *ctx, UA_String name, UA_String *out) {
    size_t oldIndex = ctx->index;
    size_t children = ctx->tokens[ctx->index].children;

    /* Skip the attributes and go to the first child */
    ctx->index += 1 + ctx->tokens[ctx->index].attributes;

    /* Find the child of the name */
    UA_StatusCode res = UA_STATUSCODE_BADDECODINGERROR;
    for(size_t i = 0; i < children; i++) {
        if(!UA_String_equal(&name, &ctx->tokens[ctx->index].name)) {
            skipXmlObject(ctx);
            continue;
        }
        *out = ctx->tokens[ctx->index].content;
        res = UA_STATUSCODE_GOOD;
        break;
    }

    ctx->index = oldIndex;
    return res;
}

static status
decodeXmlFields(ParseCtxXml *ctx, XmlDecodeEntry *entries, size_t entryCount) {
    CHECK_DATA_BOUNDS;

    if(ctx->depth >= UA_XML_ENCODING_MAX_RECURSION)
        return UA_STATUSCODE_BADENCODINGERROR;

    size_t childCount = ctx->tokens[ctx->index].children;

    /* Empty object */
    if(childCount == 0) {
        skipXmlObject(ctx);
        return UA_STATUSCODE_GOOD;
    }

    /* Go to first entry element */
    ctx->depth++;
    ctx->index += 1 + ctx->tokens[ctx->index].attributes;

    status ret = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < childCount; i++) {
        xml_token *elem = &ctx->tokens[ctx->index];
        XmlDecodeEntry *entry = NULL;
        for(size_t j = i; j < entryCount + i; j++) {
            /* Search for key, if found outer loop will be one less. Best case
             * if objectCount is in order! */
            size_t index = j % entryCount;
            if(!UA_String_equal_ignorecase(&elem->name, &entries[index].name))
                continue;
            entry = &entries[index];
            break;
        }

        /* Unknown child element */
        if(!entry)
            goto errout;

        /* An entry that was expected, but shall not be decoded.
         * Jump over it. */
        if(!entry->fieldPointer || (!entry->function && !entry->type)) {
            skipXmlObject(ctx);
            continue;
        }

        /* Duplicate child element */
        if(entry->found)
            goto errout;
        entry->found = true;

        /* Decode */
        if(entry->function) /* Specialized decoding function */
            ret = entry->function(ctx, entry->fieldPointer, entry->type);
        else /* Decode by type-kind */
            ret = decodeXmlJumpTable[entry->type->typeKind](ctx, entry->fieldPointer, entry->type);
        if(ret != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

cleanup:
    ctx->depth--;
    return ret;
errout:
    ctx->depth--;
    return UA_STATUSCODE_BADDECODINGERROR;
}

DECODE_XML(Guid) {
    CHECK_DATA_BOUNDS;
    UA_String str;
    UA_String_init(&str);
    XmlDecodeEntry entry = {UA_STRING_STATIC(UA_XML_GUID_STRING), &str,
                            NULL, false, &UA_TYPES[UA_TYPES_STRING]};
    status ret = decodeXmlFields(ctx, &entry, 1);
    ret |= UA_Guid_parse(dst, str);
    UA_String_clear(&str);
    return ret;
}

DECODE_XML(ByteString) {
    CHECK_DATA_BOUNDS;
    GET_ELEM_CONTENT;
    skipXmlObject(ctx);

    /* Empty bytestring? */
    if(length == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
    } else {
        size_t flen = 0;
        unsigned char* unB64 = UA_unbase64((const unsigned char*)data, length, &flen);
        if(!unB64)
            return UA_STATUSCODE_BADDECODINGERROR;
        dst->data = (UA_Byte*)unB64;
        dst->length = flen;
    }

    return UA_STATUSCODE_GOOD;
}

DECODE_XML(NodeId) {
    CHECK_DATA_BOUNDS;
    UA_String str;
    static UA_String identifier = UA_STRING_STATIC(UA_XML_NODEID_IDENTIFIER);
    status ret = getChildContent(ctx, identifier, &str);
    if(ret != UA_STATUSCODE_GOOD) return ret;
    skipXmlObject(ctx);
    return UA_NodeId_parseEx(dst, str, ctx->namespaceMapping);
}

DECODE_XML(ExpandedNodeId) {
    CHECK_DATA_BOUNDS;
    UA_String str;
    static UA_String expidentifier = UA_STRING_STATIC(UA_XML_EXPANDEDNODEID_IDENTIFIER);
    status ret = getChildContent(ctx, expidentifier, &str);
    if(ret != UA_STATUSCODE_GOOD) return ret;
    skipXmlObject(ctx);
    return UA_ExpandedNodeId_parseEx(dst, str, ctx->namespaceMapping,
                                     ctx->serverUrisSize, ctx->serverUris);
}

DECODE_XML(StatusCode) {
    CHECK_DATA_BOUNDS;
    UA_String str;
    static UA_String statusidentifier = UA_STRING_STATIC(UA_XML_STATUSCODE_CODE);
    status ret = getChildContent(ctx, statusidentifier, &str);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    skipXmlObject(ctx);
    UA_UInt64 out = 0;
    ret = decodeUnsigned(str.data, str.length, &out);
    if(ret != UA_STATUSCODE_GOOD || out > UA_UINT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_StatusCode)out;
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(QualifiedName) {
    CHECK_DATA_BOUNDS;

    /* Decode the elements */
    XmlDecodeEntry entries[2] = {
        {UA_STRING_STATIC(UA_XML_QUALIFIEDNAME_NAMESPACEINDEX), &dst->namespaceIndex,
         NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
        {UA_STRING_STATIC(UA_XML_QUALIFIEDNAME_NAME), &dst->name,
         NULL, false, &UA_TYPES[UA_TYPES_STRING]}
    };
    UA_StatusCode res = decodeXmlFields(ctx, entries, 2);

    /* Map the NamespaceIndex */
    if(ctx->namespaceMapping)
        dst->namespaceIndex =
            UA_NamespaceMapping_remote2Local(ctx->namespaceMapping, dst->namespaceIndex);

    return res;
}

DECODE_XML(LocalizedText) {
    CHECK_DATA_BOUNDS;

    XmlDecodeEntry entries[2] = {
        {UA_STRING_STATIC(UA_XML_LOCALIZEDTEXT_LOCALE), &dst->locale,
         NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_STRING_STATIC(UA_XML_LOCALIZEDTEXT_TEXT), &dst->text,
         NULL, false, &UA_TYPES[UA_TYPES_STRING]}
    };

    return decodeXmlFields(ctx, entries, 2);
}

/* Compare both typeId and xmlEncodingId */
static const UA_DataType *
lookupXmlType(ParseCtxXml *ctx, UA_NodeId *typeId) {
    /* Search in the builtin types */
    for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
        if(UA_NodeId_equal(typeId, &UA_TYPES[i].typeId) ||
           UA_NodeId_equal(typeId, &UA_TYPES[i].xmlEncodingId))
            return &UA_TYPES[i];
    }

    /* Search in the customTypes */
    const UA_DataTypeArray *customTypes = ctx->customTypes;
    while(customTypes) {
        for(size_t i = 0; i < customTypes->typesSize; ++i) {
            const UA_DataType *type = &customTypes->types[i];
            if(UA_NodeId_equal(typeId, &type->typeId) ||
               UA_NodeId_equal(typeId, &type->xmlEncodingId))
                return type;
        }
        customTypes = customTypes->next;
    }
    return NULL;
}

static UA_StatusCode
decodeExtensionObjectBody(ParseCtxXml *ctx, void *dst, const UA_DataType *type) {
    UA_ExtensionObject *eo = (UA_ExtensionObject*)dst;

    xml_token *tok = &ctx->tokens[ctx->index];
    if(tok->children != 1)
        return UA_STATUSCODE_BADDECODINGERROR; /* Only one child allowed */

    if(UA_NodeId_isNull(&eo->content.encoded.typeId))
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Find the datatype of the body */
    type = lookupXmlType(ctx, &eo->content.encoded.typeId);

    /* Allocate decoded content */
    void *decoded = NULL;
    if(type) {
        decoded = UA_new(type);
        if(!decoded)
            return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Jump to the first child element */
    ctx->index += 1 + tok->attributes;
    tok = &ctx->tokens[ctx->index];

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_String bs = UA_STRING_STATIC(UA_XML_EXTENSIONOBJECT_BYTESTRING);
    if(UA_String_equal(&tok->name, &bs)) {
        /* Decode binary ByteString Body */
        eo->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
        ret = decodeXmlJumpTable[UA_DATATYPEKIND_BYTESTRING](ctx, &eo->content.encoded.body, NULL);
        if(!type)
            return ret;
        UA_DecodeBinaryOptions opts;
        memset(&opts, 0, sizeof(UA_DecodeBinaryOptions));
        ret = UA_decodeBinary(&eo->content.encoded.body, decoded, type, &opts);
    } else {
        /* Decode XML Body */
        eo->encoding = UA_EXTENSIONOBJECT_ENCODED_XML;
        UA_String body = {tok->end - tok->start, (UA_Byte*)(uintptr_t)ctx->xml + tok->start};
        skipXmlObject(ctx); /* Skip over the body */
        if(!type)
            return UA_String_copy(&body, &eo->content.encoded.body);
        UA_DecodeXmlOptions opts;
        memset(&opts, 0, sizeof(UA_DecodeXmlOptions));
        opts.namespaceMapping = ctx->namespaceMapping;
        opts.serverUris = ctx->serverUris;
        opts.serverUrisSize = ctx->serverUrisSize;
        opts.customTypes = ctx->customTypes;
        ret = UA_decodeXml(&body, decoded, type, &opts);
    }

    if(ret != UA_STATUSCODE_GOOD) {
        UA_free(decoded); /* Return the un-decoded content if decoding fails */
        return UA_STATUSCODE_GOOD;
    }

    UA_ExtensionObject_clear(eo); /* Also clears the already decoded TypeId */
    UA_ExtensionObject_setValue(eo, decoded, type);
    return UA_STATUSCODE_GOOD;
}

DECODE_XML(ExtensionObject) {
    CHECK_DATA_BOUNDS;
    xml_token *tok = &ctx->tokens[ctx->index];
    if(tok->children == 0)
        return UA_STATUSCODE_GOOD; /* _NO_BODY */
    dst->encoding = UA_EXTENSIONOBJECT_ENCODED_XML; /* default so the typeId gets cleaned up */
    XmlDecodeEntry entries[2] = {
        {UA_STRING_STATIC(UA_XML_EXTENSIONOBJECT_TYPEID), &dst->content.encoded.typeId,
         NULL, false, &UA_TYPES[UA_TYPES_NODEID]},
        {UA_STRING_STATIC(UA_XML_EXTENSIONOBJECT_BODY), dst,
         decodeExtensionObjectBody, false, NULL},
    };
    return decodeXmlFields(ctx, entries, 2);
}

static status
Array_decodeXml(ParseCtxXml *ctx, size_t *dstSize, const UA_DataType *type) {
    /* Allocate memory */
    size_t length = ctx->tokens[ctx->index].children;
    void **dst = (void**)((uintptr_t)dstSize + sizeof(void*));
    *dst = UA_Array_new(length, type);
    if(!*dst)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *dstSize = length;

    /* Go to first array member. */
    ctx->index += 1 + ctx->tokens[ctx->index].attributes;

    /* Decode array members */
    uintptr_t ptr = (uintptr_t)*dst;
    for(size_t i = 0; i < length; ++i) {
        status ret = decodeXmlJumpTable[type->typeKind](ctx, (void*)ptr, type);
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
        ptr += type->memSize;
    }

    return UA_STATUSCODE_GOOD;
}

static const UA_DataType *
lookupTypeByName(ParseCtxXml *ctx, UA_String typeName) {
    /* Search in the builtin types */
    for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
        if(strncmp((char*)typeName.data, UA_TYPES[i].typeName, typeName.length) == 0)
            return &UA_TYPES[i];
    }

    /* Search in the customTypes */
    const UA_DataTypeArray *customTypes = ctx->customTypes;
    while(customTypes) {
        for(size_t i = 0; i < customTypes->typesSize; ++i) {
            const UA_DataType *type = &customTypes->types[i];
            if(strncmp((char*)typeName.data, type->typeName, typeName.length) == 0)
                return type;
        }
        customTypes = customTypes->next;
    }
    return NULL;
}

static void
unwrapVariantExtensionObject(UA_Variant *dst, UA_Boolean isArray) {
    if(dst->type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
        return;
    if(isArray && dst->arrayLength == 0)
        return;

    UA_ExtensionObject *eo = (UA_ExtensionObject*)dst->data;
    if(eo->encoding != UA_EXTENSIONOBJECT_DECODED)
        return;

    const UA_DataType *type = eo->content.decoded.type;

    /* Scalar */
    if(!isArray) {
        dst->data = eo->content.decoded.data;
        dst->type = type;
        UA_free(eo);
        return;
    }

    /* Array. Check that all members can be unpacked */
    for(size_t i = 0; i < dst->arrayLength; i++, eo++) {
        if(eo->encoding != UA_EXTENSIONOBJECT_DECODED)
            return;
        if(eo->content.decoded.type != type)
            return;
    }

    /* Allocate the array */
    void *unpacked = UA_calloc(dst->arrayLength, type->memSize);
    if(!unpacked)
        return;

    /* Unpack the content and set the new array */
    uintptr_t uptr = (uintptr_t)unpacked;
    eo = (UA_ExtensionObject*)dst->data;
    for(size_t i = 0; i < dst->arrayLength; i++, eo++) {
        /* Move the value content */
        memcpy((void*)uptr, eo->content.decoded.data, type->memSize);
        UA_free(eo->content.decoded.data); /* Free the old value location */
        uptr += type->memSize;
    }
    UA_free(dst->data); /* Remove the old array of ExtensionObjects */
    dst->data = unpacked;
    dst->type = type;
}

static UA_StatusCode
decodeMatrixVariant(ParseCtxXml *ctx, UA_Variant *dst) {
    /* The <Matrix> token needs two children: <Dimensions> and <Elements> */
    xml_token *tok = &ctx->tokens[ctx->index];
    if(tok->children != 2)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Jump to the child of the <Matrix> token */
    ctx->index += 1 + ctx->tokens[ctx->index].attributes;
    tok = &ctx->tokens[ctx->index];

    UA_assert(tok->type == XML_TOKEN_ELEMENT);
    static UA_String dimName = UA_STRING_STATIC("Dimensions");
    if(!UA_String_equal(&tok->name, &dimName))
        return UA_STATUSCODE_BADDECODINGERROR;

    UA_StatusCode ret =
        Array_decodeXml(ctx, &dst->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    UA_assert(tok->type == XML_TOKEN_ELEMENT);
    static UA_String elemName = UA_STRING_STATIC("Elements");
    tok = &ctx->tokens[ctx->index];
    if(!UA_String_equal(&tok->name, &elemName))
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Get the type of the first element */
    size_t oldIndex = ctx->index;
    ctx->index += 1 + ctx->tokens[ctx->index].attributes;
    tok = &ctx->tokens[ctx->index];
    UA_assert(tok->type == XML_TOKEN_ELEMENT);

    UA_String typeName = tok->name;
    dst->type = lookupTypeByName(ctx, typeName);
    if(!dst->type)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Decode the array */
    ctx->index = oldIndex;
    ret = Array_decodeXml(ctx, &dst->arrayLength, dst->type);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Check that the ArrayDimensions match */
    size_t dimLen = 1;
    for(size_t i = 0; i < dst->arrayDimensionsSize; i++)
        dimLen *= dst->arrayDimensions[i];

    return (dimLen == dst->arrayLength) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADDECODINGERROR;
}

DECODE_XML(Variant) {
    CHECK_DATA_BOUNDS;

    if(ctx->depth >= UA_XML_ENCODING_MAX_RECURSION)
        return UA_STATUSCODE_BADENCODINGERROR;

    xml_token *tok = &ctx->tokens[ctx->index];
    if(tok->children == 0)
        return UA_STATUSCODE_GOOD;
    if(tok->children != 1)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Move forward to the content */
    if(ctx->index + 2 >= ctx->tokensSize)
        return UA_STATUSCODE_BADDECODINGERROR;

    ctx->index += 1 + ctx->tokens[ctx->index].attributes;
    tok = &ctx->tokens[ctx->index];
    static UA_String valName = UA_STRING_STATIC("Value");
    if(!UA_String_equal(&tok->name, &valName))
        return UA_STATUSCODE_BADDECODINGERROR;
    if(tok->children != 1)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Jump to the child of the <Value> token */
    ctx->depth++;
    ctx->index += 1 + ctx->tokens[ctx->index].attributes;
    tok = &ctx->tokens[ctx->index];

    /* Special case for multi-dimensional arrays */
    static UA_String matrName = UA_STRING_STATIC("Matrix");
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(UA_String_equal(&tok->name, &matrName)) {
        ret = decodeMatrixVariant(ctx, dst);
        unwrapVariantExtensionObject(dst, true);
        ctx->depth--;
        return ret;
    }

    /* Get the Data type / array type */
    UA_Boolean isArray = false;
    static char *lo = "ListOf";
    UA_String typeName = tok->name;
    if(tok->name.length > strlen(lo) &&
       strncmp((char*)tok->name.data, lo, strlen(lo)) == 0) {
        isArray = true;
        typeName.data += strlen(lo);
        typeName.length -= strlen(lo);
    }

    /* Look up the DataType from the name */
    dst->type = lookupTypeByName(ctx, typeName);
    if(!dst->type) {
        ctx->depth--;
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Decode */
    if(!isArray) {
        dst->data = UA_new(dst->type);
        if(!dst->data) {
            ctx->depth--;
            return UA_STATUSCODE_BADDECODINGERROR;
        }
        ret = decodeXmlJumpTable[dst->type->typeKind](ctx, dst->data, dst->type);
    } else {
        ret = Array_decodeXml(ctx, &dst->arrayLength, dst->type);
    }

    /* Unwrap ExtensionObject values in the variant */
    unwrapVariantExtensionObject(dst, isArray);

    ctx->depth--;
    return ret;
}

static status
decodeXmlStructure(ParseCtxXml *ctx, void *dst, const UA_DataType *type) {
    /* Check the recursion limit */
    if(ctx->depth >= UA_XML_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    status ret = UA_STATUSCODE_GOOD;
    u8 membersSize = type->membersSize;
    UA_STACKARRAY(XmlDecodeEntry, entries, membersSize);
    for(size_t i = 0; i < membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        entries[i].type = mt;
        entries[i].name = UA_STRING((char*)(uintptr_t)m->memberName);
        entries[i].found = false;
        ptr += m->padding;
        entries[i].fieldPointer = (void*)ptr;
        if(!m->isArray) {
            entries[i].function = NULL;
            ptr += mt->memSize;
        } else {
            entries[i].function = (decodeXmlSignature)Array_decodeXml;
            ptr += sizeof(size_t) + sizeof(void*);
        }
    }

    ret = decodeXmlFields(ctx, entries, membersSize);

    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth--;
    return ret;
}

static status
decodeXmlNotImplemented(ParseCtxXml *ctx, void *dst, const UA_DataType *type) {
    (void)dst, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const decodeXmlSignature decodeXmlJumpTable[UA_DATATYPEKINDS] = {
    (decodeXmlSignature)Boolean_decodeXml,          /* Boolean */
    (decodeXmlSignature)SByte_decodeXml,            /* SByte */
    (decodeXmlSignature)Byte_decodeXml,             /* Byte */
    (decodeXmlSignature)Int16_decodeXml,            /* Int16 */
    (decodeXmlSignature)UInt16_decodeXml,           /* UInt16 */
    (decodeXmlSignature)Int32_decodeXml,            /* Int32 */
    (decodeXmlSignature)UInt32_decodeXml,           /* UInt32 */
    (decodeXmlSignature)Int64_decodeXml,            /* Int64 */
    (decodeXmlSignature)UInt64_decodeXml,           /* UInt64 */
    (decodeXmlSignature)Float_decodeXml,            /* Float */
    (decodeXmlSignature)Double_decodeXml,           /* Double */
    (decodeXmlSignature)String_decodeXml,           /* String */
    (decodeXmlSignature)DateTime_decodeXml,         /* DateTime */
    (decodeXmlSignature)Guid_decodeXml,             /* Guid */
    (decodeXmlSignature)ByteString_decodeXml,       /* ByteString */
    (decodeXmlSignature)decodeXmlNotImplemented,    /* XmlElement */
    (decodeXmlSignature)NodeId_decodeXml,           /* NodeId */
    (decodeXmlSignature)ExpandedNodeId_decodeXml,   /* ExpandedNodeId */
    (decodeXmlSignature)StatusCode_decodeXml,       /* StatusCode */
    (decodeXmlSignature)QualifiedName_decodeXml,    /* QualifiedName */
    (decodeXmlSignature)LocalizedText_decodeXml,    /* LocalizedText */
    (decodeXmlSignature)ExtensionObject_decodeXml,  /* ExtensionObject */
    (decodeXmlSignature)decodeXmlNotImplemented,    /* DataValue */
    (decodeXmlSignature)Variant_decodeXml,          /* Variant */
    (decodeXmlSignature)decodeXmlNotImplemented,    /* DiagnosticInfo */
    (decodeXmlSignature)decodeXmlNotImplemented,    /* Decimal */
    (decodeXmlSignature)Int32_decodeXml,            /* Enum */
    (decodeXmlSignature)decodeXmlStructure,         /* Structure */
    (decodeXmlSignature)decodeXmlNotImplemented,    /* Structure with optional fields */
    (decodeXmlSignature)decodeXmlNotImplemented,    /* Union */
    (decodeXmlSignature)decodeXmlNotImplemented     /* BitfieldCluster */
};

UA_StatusCode
UA_decodeXml(const UA_ByteString *src, void *dst, const UA_DataType *type,
             const UA_DecodeXmlOptions *options) {
    if(!dst || !src || !type)
        return UA_STATUSCODE_BADARGUMENTSMISSING;

    /* Tokenize. Add a fake wrapper element if options->unwrapped is enabled. */
    unsigned tokensSize = 63;
    xml_token tokenbuf[64];
    xml_token *tokens = tokenbuf;

    xml_result res = xml_tokenize((char*)src->data, (unsigned)src->length,
                                  tokens + 1, tokensSize);
    if(res.error == XML_ERROR_OVERFLOW) {
        tokens = (xml_token*)UA_malloc(sizeof(xml_token) * (res.num_tokens + 1));
        if(!tokens)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = xml_tokenize((char*)src->data, (unsigned)src->length,
                           tokens + 1, res.num_tokens);
    }

    if(res.error != XML_ERROR_NONE || res.num_tokens == 0) {
        if(tokens != tokenbuf)
            UA_free(tokens);
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Set up the context */
    ParseCtxXml ctx;
    memset(&ctx, 0, sizeof(ParseCtxXml));
    ctx.xml = (const char*)src->data;
    ctx.tokens = tokens;
    ctx.tokensSize = res.num_tokens;
    if(options) {
        ctx.customTypes = options->customTypes;
        ctx.namespaceMapping = options->namespaceMapping;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
    }

    if(options && options->unwrapped) {
        /* Set up the fake wrapper element */
        xml_token *tok = tokens;
        memset(tok, 0, sizeof(xml_token));
        tok->type = XML_TOKEN_ELEMENT;
        tok->name = UA_STRING((char*)(uintptr_t)type->typeName);
        tok->children = 1;
        tok->start = 0;
        tok->end = (unsigned)src->length;
        ctx.tokensSize++;
    } else {
        ctx.tokens++; /* Skip the first token */
    }

    /* Decode */
    memset(dst, 0, type->memSize); /* Initialize the value */
    UA_StatusCode ret = decodeXmlJumpTable[type->typeKind](&ctx, dst, type);
    if(ret != UA_STATUSCODE_GOOD)
        UA_clear(dst, type);

    /* Clean up */
    if(tokens != tokenbuf)
        UA_free(tokens);
    return ret;
}

/**** amalgamated original file "/src/server/ua_discovery.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015-2016, 2019 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */


#ifdef UA_ENABLE_DISCOVERY

void
UA_DiscoveryManager_setState(UA_DiscoveryManager *dm,
                             UA_LifecycleState state) {
    /* Check if open connections remain */
    if(state == UA_LIFECYCLESTATE_STOPPING ||
       state == UA_LIFECYCLESTATE_STOPPED) {
        state = UA_LIFECYCLESTATE_STOPPED;
#ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD 
        if(UA_DiscoveryManager_getMdnsConnectionCount() > 0)
            state = UA_LIFECYCLESTATE_STOPPING;
#endif

        for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
            if(dm->registerRequests[i].client != NULL)
                state = UA_LIFECYCLESTATE_STOPPING;
        }
    }

    /* No change */
    if(state == dm->sc.state)
        return;

    /* Set the new state and notify */
    dm->sc.state = state;
    if(dm->sc.notifyState)
        dm->sc.notifyState(&dm->sc, state);
}

static UA_StatusCode
UA_DiscoveryManager_clear(struct UA_ServerComponent *sc) {
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;

    if(sc->state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_ERROR(sc->server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Cannot delete the DiscoveryManager because "
                     "it is not stopped");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    registeredServer *rs, *rs_tmp;
    LIST_FOREACH_SAFE(rs, &dm->registeredServers, pointers, rs_tmp) {
        LIST_REMOVE(rs, pointers);
        UA_RegisteredServer_clear(&rs->registeredServer);
        UA_free(rs);
    }

# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_DiscoveryManager_clearMdns(dm);
# endif /* UA_ENABLE_DISCOVERY_MULTICAST */

    return UA_STATUSCODE_GOOD;
}

/* Cleanup server registration: If the semaphore file path is set, then it just
 * checks the existence of the file. When it is deleted, the registration is
 * removed. If there is no semaphore file, then the registration will be removed
 * if it is older than 60 minutes. */
static void
UA_DiscoveryManager_cleanupTimedOut(UA_Server *server, void *data) {
    UA_EventLoop *el = server->config.eventLoop;
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)data;

    /* TimedOut gives the last DateTime at which we must have seen the
     * registered server. Otherwise it is timed out. */
    UA_DateTime timedOut = el->dateTime_nowMonotonic(el);
    if(server->config.discoveryCleanupTimeout)
        timedOut -= server->config.discoveryCleanupTimeout * UA_DATETIME_SEC;

    registeredServer *current, *temp;
    LIST_FOREACH_SAFE(current, &dm->registeredServers, pointers, temp) {
        UA_Boolean semaphoreDeleted = false;

#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
        if(current->registeredServer.semaphoreFilePath.length) {
            size_t fpSize = current->registeredServer.semaphoreFilePath.length+1;
            char* filePath = (char *)UA_malloc(fpSize);
            if(filePath) {
                memcpy(filePath, current->registeredServer.semaphoreFilePath.data,
                       current->registeredServer.semaphoreFilePath.length );
                filePath[current->registeredServer.semaphoreFilePath.length] = '\0';
                semaphoreDeleted = UA_fileExists(filePath) == false;
                UA_free(filePath);
            } else {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "Cannot check registration semaphore. Out of memory");
            }
        }
#endif

        if(semaphoreDeleted ||
           (server->config.discoveryCleanupTimeout &&
            current->lastSeen < timedOut)) {
            if(semaphoreDeleted) {
                UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                            "Registration of server with URI %S is removed because "
                            "the semaphore file '%S' was deleted",
                            current->registeredServer.serverUri,
                            current->registeredServer.semaphoreFilePath);
            } else {
                // cppcheck-suppress unreadVariable
                UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                            "Registration of server with URI %S has timed out "
                            "and is removed", current->registeredServer.serverUri);
            }
            LIST_REMOVE(current, pointers);
            UA_RegisteredServer_clear(&current->registeredServer);
            UA_free(current);
            dm->registeredServersSize--;
        }
    }
}

static void
UA_DiscoveryManager_cyclicTimer(UA_Server *server, void *data) {
    UA_DiscoveryManager_cleanupTimedOut(server, data);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_DiscoveryManager_mdnsCyclicTimer(server, data);
#endif
}

static UA_StatusCode
UA_DiscoveryManager_start(struct UA_ServerComponent *sc,
                          UA_Server *server) {
    if(sc->state != UA_LIFECYCLESTATE_STOPPED)
        return UA_STATUSCODE_BADINTERNALERROR;

    sc->server = server; /* Set the backpointer */

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_DiscoveryManager_resetServerOnNetworkRecordCounter(dm);
#endif /* UA_ENABLE_DISCOVERY_MULTICAST */

    UA_StatusCode res =
        addRepeatedCallback(server, UA_DiscoveryManager_cyclicTimer,
                            dm, 1000.0, &dm->discoveryCallbackId);
    if(res != UA_STATUSCODE_GOOD)
        return res;

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    if(server->config.mdnsEnabled)
        UA_DiscoveryManager_startMulticast(dm);
#endif

    UA_DiscoveryManager_setState(dm, UA_LIFECYCLESTATE_STARTED);
    return UA_STATUSCODE_GOOD;
}

static void
UA_DiscoveryManager_stop(struct UA_ServerComponent *sc) {
    if(sc->state != UA_LIFECYCLESTATE_STARTED)
        return;

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;

    /* Set STOPPING early so that CLOSING callbacks (fired by stopMulticast
     * below) do not trigger UA_DiscoveryManager_startMulticast and re-open
     * connections that would prevent the DM from reaching STOPPED. */
    sc->state = UA_LIFECYCLESTATE_STOPPING;

    removeCallback(dm->sc.server, dm->discoveryCallbackId);

    /* Cancel all outstanding register requests */
    for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
        if(dm->registerRequests[i].client == NULL)
            continue;
        UA_Client_disconnectSecureChannelAsync(dm->registerRequests[i].client);
    }

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    if(sc->server->config.mdnsEnabled)
        UA_DiscoveryManager_stopMulticast(dm);
#endif

    UA_DiscoveryManager_setState(dm, UA_LIFECYCLESTATE_STOPPED);
}

UA_ServerComponent *
UA_DiscoveryManager_new(void) {
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        UA_calloc(1, sizeof(UA_DiscoveryManager));
    if(!dm)
        return NULL;

    dm->sc.name = UA_STRING("discovery");
    dm->sc.start = UA_DiscoveryManager_start;
    dm->sc.stop = UA_DiscoveryManager_stop;
    dm->sc.clear = UA_DiscoveryManager_clear;
    return &dm->sc;
}

/********************************/
/* Register at Discovery Server */
/********************************/

static void
asyncRegisterRequest_clear(void *_, void *context) {
    asyncRegisterRequest *ar = (asyncRegisterRequest*)context;
    UA_DiscoveryManager *dm = ar->dm;

    UA_String_clear(&ar->semaphoreFilePath);
    if(ar->client)
        UA_Client_delete(ar->client);
    memset(ar, 0, sizeof(asyncRegisterRequest));

    /* The Discovery manager is fully stopped? */
    UA_DiscoveryManager_setState(dm, dm->sc.state);
}

static void
asyncRegisterRequest_clearAsync(asyncRegisterRequest *ar) {
    UA_Server *server = ar->server;
    UA_ServerConfig *sc = &server->config;
    UA_EventLoop *el = sc->eventLoop;

    ar->cleanupCallback.callback = asyncRegisterRequest_clear;
    ar->cleanupCallback.application = server;
    ar->cleanupCallback.context = ar;
    el->addDelayedCallback(el, &ar->cleanupCallback);
}

static void
setupRegisterRequest(asyncRegisterRequest *ar, UA_RequestHeader *rh,
                     UA_RegisteredServer *rs) {
    UA_ServerConfig *sc = &ar->dm->sc.server->config;

    rh->timeoutHint = 10000;

    rs->isOnline = !ar->unregister;
    rs->serverUri = sc->applicationDescription.applicationUri;
    rs->productUri = sc->applicationDescription.productUri;
    rs->serverType = sc->applicationDescription.applicationType;
    rs->gatewayServerUri = sc->applicationDescription.gatewayServerUri;
    rs->semaphoreFilePath = ar->semaphoreFilePath;

    rs->serverNames = &sc->applicationDescription.applicationName;
    rs->serverNamesSize = 1;

    /* Mirror the discovery URLs from the server config (includes hostnames from
     * the network layers) */
    rs->discoveryUrls = sc->applicationDescription.discoveryUrls;
    rs->discoveryUrlsSize = sc->applicationDescription.discoveryUrlsSize;
}

static void
registerAsyncResponse(UA_Client *client, void *userdata,
                      UA_UInt32 requestId, void *resp) {
    asyncRegisterRequest *ar = (asyncRegisterRequest*)userdata;
    const UA_ServerConfig *sc = &ar->dm->sc.server->config;
    UA_Response *response = (UA_Response*)resp;
    const char *regtype = (ar->register2) ? "RegisterServer2" : "RegisterServer";

    /* Success registering? */
    if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(sc->logging, UA_LOGCATEGORY_SERVER, "%s succeeded", regtype);
        goto done;
    }

    UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_SERVER,
                   "%s failed with statuscode %s", regtype,
                   UA_StatusCode_name(response->responseHeader.serviceResult));

    /* RegisterServer already failed. Do not retry indefinitely. */
    if(!ar->register2)
        goto done;

    /* Try RegisterServer next */
    ar->register2 = false;

    /* Try RegisterServer immediately if we can.
     * Otherwise wait for the next state callback. */
    UA_SecureChannelState ss;
    UA_Client_getState(client, &ss, NULL, NULL);
    if(!ar->shutdown && ss == UA_SECURECHANNELSTATE_OPEN) {
        UA_RegisterServerRequest request;
        UA_RegisterServerRequest_init(&request);
        setupRegisterRequest(ar, &request.requestHeader, &request.server);
        UA_StatusCode res =
            __UA_Client_AsyncService(client, &request,
                                     &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST],
                                     registerAsyncResponse,
                                     &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE], ar, NULL);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR((const UA_Logger *)&sc->logging, UA_LOGCATEGORY_CLIENT,
                         "RegisterServer failed with statuscode %s",
                         UA_StatusCode_name(res));
            goto done;
        }
    }

    return;

 done:
    /* Close the client connection, will be cleaned up in the client state
     * callback when closing is complete */
    ar->shutdown = true;
    UA_Client_disconnectSecureChannelAsync(ar->client);
}

static void
discoveryClientStateCallback(UA_Client *client,
                             UA_SecureChannelState channelState,
                             UA_SessionState sessionState,
                             UA_StatusCode connectStatus) {
    asyncRegisterRequest *ar = (asyncRegisterRequest*)
        UA_Client_getContext(client);
    UA_ServerConfig *sc = &ar->dm->sc.server->config;

    /* Connection failed */
    if(connectStatus != UA_STATUSCODE_GOOD) {
        if(connectStatus != UA_STATUSCODE_BADCONNECTIONCLOSED) {
            UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
                         "Could not connect to the Discovery server with error %s",
                         UA_StatusCode_name(connectStatus));
        }

        /* Connection fully closed */
        if(channelState == UA_SECURECHANNELSTATE_CLOSED) {
            if(!ar->connectSuccess || ar->shutdown) {
                asyncRegisterRequest_clearAsync(ar); /* Clean up */
            } else {
                ar->connectSuccess = false;
                UA_Client_connectAsync(client, NULL);   /* Reconnect */
            }
        }
        return;
    }

    /* Wait until the SecureChannel is open */
    if(channelState != UA_SECURECHANNELSTATE_OPEN)
        return;

    /* We have at least succeeded to connect */
    ar->connectSuccess = true;

    /* Is this the encrypted SecureChannel already? (We might have to wait for
     * the second connection after the FindServers handshake */
    UA_MessageSecurityMode msm = UA_MESSAGESECURITYMODE_INVALID;
    UA_Client_getConnectionAttribute_scalar(client, UA_QUALIFIEDNAME(0, "securityMode"),
                                            &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE],
                                            &msm);
#ifdef UA_ENABLE_ENCRYPTION
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    if(cc->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
       msm != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return;
#endif

    const UA_DataType *reqType;
    const UA_DataType *respType;
    UA_RegisterServerRequest reg1;
    UA_RegisterServer2Request reg2;
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_ExtensionObject mdnsConfig;
#endif
    void *request;

    /* Prepare the request. This does not allocate memory */
    if(ar->register2) {
        UA_RegisterServer2Request_init(&reg2);
        setupRegisterRequest(ar, &reg2.requestHeader, &reg2.server);
        reqType = &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST];
        respType = &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE];
        request = &reg2;

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
        /* Set the configuration that is only available for
         * UA_RegisterServer2Request */
        UA_ExtensionObject_setValueNoDelete(&mdnsConfig, &sc->mdnsConfig,
                                            &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION]);
        reg2.discoveryConfigurationSize = 1;
        reg2.discoveryConfiguration = &mdnsConfig;
#endif
    } else {
        UA_RegisterServerRequest_init(&reg1);
        setupRegisterRequest(ar, &reg1.requestHeader, &reg1.server);
        reqType = &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST];
        respType = &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE];
        request = &reg1;
    }

    /* Try to call RegisterServer2 */
    UA_StatusCode res =
        __UA_Client_AsyncService(client, request, reqType, registerAsyncResponse,
                                 respType, ar, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        /* Close the client connection, will be cleaned up in the client state
         * callback when closing is complete */
        UA_Client_disconnectSecureChannelAsync(ar->client);
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_CLIENT,
                     "RegisterServer2 failed with statuscode %s",
                     UA_StatusCode_name(res));
    }
}

static UA_StatusCode
UA_Server_register(UA_Server *server, UA_ClientConfig *cc, UA_Boolean unregister,
                   const UA_String discoveryServerUrl,
                   const UA_String semaphoreFilePath) {
    /* Get the discovery manager */
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm) {
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check that the discovery manager is running */
    UA_ServerConfig *sc = &server->config;
    if(dm->sc.state != UA_LIFECYCLESTATE_STARTED) {
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
                     "The server must be started for registering");
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Find a free slot for storing the async request information */
    asyncRegisterRequest *ar = NULL;
    for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
        if(dm->registerRequests[i].client == NULL) {
            ar = &dm->registerRequests[i];
            break;
        }
    }
    if(!ar) {
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
                     "Too many outstanding register requests. Cannot proceed.");
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Use the EventLoop from the server for the client */
    if(cc->eventLoop && !cc->externalEventLoop)
        cc->eventLoop->free(cc->eventLoop);
    cc->eventLoop = sc->eventLoop;
    cc->externalEventLoop = true;

    /* Set the state callback method and context */
    cc->stateCallback = discoveryClientStateCallback;
    cc->clientContext = ar;

    /* If it's not already set, use encryption by default */
    if(cc->securityMode == UA_MESSAGESECURITYMODE_INVALID) {
#ifdef UA_ENABLE_ENCRYPTION
        cc->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
#else
        cc->securityMode = UA_MESSAGESECURITYMODE_NONE;
#endif
    }

    /* Open only a SecureChannel */
    cc->noSession = true;

    /* Move the endpoint url */
    UA_String_clear(&cc->endpointUrl);
    UA_String_copy(&discoveryServerUrl, &cc->endpointUrl);

    /* Instantiate the client */
    ar->client = UA_Client_newWithConfig(cc);
    if(!ar->client) {
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Zero out the supplied config */
    memset(cc, 0, sizeof(UA_ClientConfig));

    /* Finish setting up the context */
    ar->server = server;
    ar->dm = dm;
    ar->unregister = unregister;
    ar->register2 = true; /* Try register2 first */
    UA_String_copy(&semaphoreFilePath, &ar->semaphoreFilePath);

    /* Connect asynchronously. The register service is called once the
     * connection is open. */
    ar->connectSuccess = false;
    return UA_Client_connectAsync(ar->client, NULL);
}

UA_StatusCode
UA_Server_registerDiscovery(UA_Server *server, UA_ClientConfig *cc,
                            const UA_String discoveryServerUrl,
                            const UA_String semaphoreFilePath) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "Registering at the DiscoveryServer: %S", discoveryServerUrl);
    lockServer(server);
    UA_StatusCode res =
        UA_Server_register(server, cc, false, discoveryServerUrl, semaphoreFilePath);
    unlockServer(server);
    return res;
}

UA_StatusCode
UA_Server_deregisterDiscovery(UA_Server *server, UA_ClientConfig *cc,
                              const UA_String discoveryServerUrl) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "Deregistering at the DiscoveryServer: %S", discoveryServerUrl);
    lockServer(server);
    UA_StatusCode res =
        UA_Server_register(server, cc, true, discoveryServerUrl, UA_STRING_NULL);
    unlockServer(server);
    return res;
}

#endif /* UA_ENABLE_DISCOVERY */

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_common.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */



#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)

#include <openssl/x509.h>
#include <openssl/evp.h>

#define UA_SHA1_LENGTH 20

_UA_BEGIN_DECLS


#if !defined(OPENSSL_VERSION_NUMBER)
#error "OPENSSL_VERSION_NUMBER is not defined."
#endif

#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
#define X509_STORE_CTX_set0_trusted_stack(STORE_CTX, CTX_SKTRUSTED) X509_STORE_CTX_trusted_stack(STORE_CTX, CTX_SKTRUSTED)
#endif

#if OPENSSL_VERSION_NUMBER < 0x1010000fL || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050000fL)
#define X509_STORE_CTX_get_check_issued(STORE_CTX) STORE_CTX->check_issued
#endif

#if OPENSSL_VERSION_NUMBER < 0x1010000fL || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050000fL)
#define get_pkey_rsa(evp) ((evp)->pkey.rsa)
#else
#define get_pkey_rsa(evp) EVP_PKEY_get0_RSA(evp)
#endif

#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER)
#define X509_get0_subject_key_id(PX509_CERT) (const ASN1_OCTET_STRING *)X509_get_ext_d2i(PX509_CERT, NID_subject_key_identifier, NULL, NULL);
#endif

#if OPENSSL_VERSION_NUMBER < 0x2000000fL || defined(LIBRESSL_VERSION_NUMBER)
#define get_error_line_data(pFile, pLine, pData, pFlags) ERR_get_error_line_data(pFile, pLine, pData, pFlags)
#else
#define get_error_line_data(pFile, pLine, pData, pFlags) ERR_get_error_all(pFile, pLine, NULL, pData, pFlags)
#endif

void saveDataToFile(const char *fileName, const UA_ByteString *str);
void UA_Openssl_Init(void);

UA_StatusCode
UA_copyCertificate(UA_ByteString *dst, const UA_ByteString *src);

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(const UA_ByteString *msg,
                                       X509 *publicKeyX509,
                                       const UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_RSA_PSS_SHA256_Verify (const UA_ByteString * msg,
                                  X509 *publicKeyX509,
                                  const UA_ByteString * signature);

UA_StatusCode
UA_Openssl_X509_GetCertificateThumbprint(const UA_ByteString *certficate,
                                         UA_ByteString *pThumbprint,
                                         bool bThumbPrint);
UA_StatusCode
UA_Openssl_RSA_Oaep_Decrypt(UA_ByteString *data,
                            EVP_PKEY *privateKey);

UA_StatusCode
UA_Openssl_RSA_Oaep_Sha2_Decrypt (UA_ByteString *data,
                            EVP_PKEY *privateKey);

UA_StatusCode
UA_Openssl_RSA_OAEP_Encrypt(UA_ByteString *data, /* The data that is encrypted.
                                                    The encrypted data will overwrite
                                                    the data that was supplied.  */
                             size_t paddingSize, X509 *publicX509);

UA_StatusCode
UA_Openssl_RSA_OAEP_SHA2_Encrypt (UA_ByteString * data,
                                  size_t          paddingSize,
                                  X509 *          publicX509);

UA_StatusCode
UA_Openssl_Random_Key_PSHA256_Derive(const UA_ByteString *secret,
                                     const UA_ByteString *seed,
                                     UA_ByteString *out);

UA_StatusCode
UA_Openssl_RSA_Public_GetKeyLength(X509 *publicKeyX509, UA_Int32 *keyLen);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(const UA_ByteString *data,
                                     EVP_PKEY *privateKey,
                                     UA_ByteString *outSignature);

UA_StatusCode
UA_Openssl_RSA_PSS_SHA256_Sign (const UA_ByteString * message,
                                EVP_PKEY * privateKey,
                                UA_ByteString *       outSignature);

UA_StatusCode
UA_OpenSSL_ECC_NISTP256_GenerateKey (EVP_PKEY ** keyPairOut,
                                     UA_ByteString * keyPublicEncOut);

UA_StatusCode
UA_OpenSSL_ECC_DeriveKeys (const int curveID,
                           char * hashAlgorithm,
                           const UA_ApplicationType applicationType,
                           EVP_PKEY * localEphemeralKeyPair,
                           const UA_ByteString * key1,
                           const UA_ByteString * key2,
                           UA_ByteString * out);

UA_StatusCode
UA_Openssl_ECDSA_SHA256_Sign (const UA_ByteString * message,
                              EVP_PKEY * privateKey,
                              UA_ByteString * outSignature);

UA_StatusCode
UA_Openssl_ECDSA_SHA256_Verify (const UA_ByteString * message,
                                X509 * publicKeyX509,
                                const UA_ByteString * signature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Decrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Encrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

UA_StatusCode
UA_OpenSSL_X509_compare(const UA_ByteString *cert, const X509 *b);

UA_StatusCode
UA_Openssl_RSA_Private_GetKeyLength(EVP_PKEY *privateKey,
                                    UA_Int32 *keyLen) ;

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(const UA_ByteString *msg,
                                      X509 *publicKeyX509,
                                      const UA_ByteString *signature);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(const UA_ByteString *message,
                                   EVP_PKEY *privateKey,
                                   UA_ByteString *outSignature);
UA_StatusCode
UA_Openssl_Random_Key_PSHA1_Derive(const UA_ByteString *secret,
                                   const UA_ByteString *seed,
                                   UA_ByteString *out);
UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Verify(const UA_ByteString *message,
                            const UA_ByteString *key,
                            const UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Sign(const UA_ByteString *message,
                          const UA_ByteString *key,
                          UA_ByteString *signature);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Decrypt(UA_ByteString *data,
                                 EVP_PKEY *privateKey);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Encrypt(UA_ByteString *data,
                                 size_t paddingSize,
                                 X509 *publicX509);

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Decrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Encrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

UA_StatusCode
UA_OpenSSL_CreateSigningRequest(EVP_PKEY *localPrivateKey,
                                EVP_PKEY **csrLocalPrivateKey,
                                UA_SecurityPolicy *securityPolicy,
                                const UA_String *subjectName,
                                const UA_ByteString *nonce,
                                UA_ByteString *csr,
                                UA_ByteString *newPrivateKey);

EVP_PKEY *
UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey);

/* Check for the correct RSA/ECC certificate */
/* keyType == EVP_PKEY_NONE omits the check */
/* EVP_PKEY_RSA */
/* EVP_PKEY_EC */
/* EVP_PKEY_ED25519 */
/* EVP_PKEY_ED448 */
X509 *
UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate,
                           int keyType);

X509 *
UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate);

X509 *
UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate);

X509_CRL *
UA_OpenSSL_LoadCrl(const UA_ByteString *crl);

X509_CRL *
UA_OpenSSL_LoadDerCrl(const UA_ByteString *crl);

X509_CRL *
UA_OpenSSL_LoadPemCrl(const UA_ByteString *crl);

UA_StatusCode
UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate,
                                UA_ByteString *target,
                                int keyType);


UA_StatusCode
UA_OpenSSL_ECC_NISTP384_GenerateKey (EVP_PKEY ** keyPairOut,
                                     UA_ByteString * keyPublicEncOut);

UA_StatusCode
UA_Openssl_ECDSA_SHA384_Sign (const UA_ByteString * message,
                              EVP_PKEY * privateKey,
                              UA_ByteString * outSignature);

UA_StatusCode
UA_Openssl_ECDSA_SHA384_Verify (const UA_ByteString * message,
                                X509 * publicKeyX509,
                                const UA_ByteString * signature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA384_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA384_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature);


UA_StatusCode
UA_OpenSSL_ECC_BRAINPOOLP256R1_GenerateKey (EVP_PKEY ** keyPairOut,
                                             UA_ByteString * keyPublicEncOut);


UA_StatusCode
UA_OpenSSL_ECC_BRAINPOOLP384R1_GenerateKey (EVP_PKEY ** keyPairOut,
                                             UA_ByteString * keyPublicEncOut);


/* EdDSA Ed25519 signing and verification */
UA_StatusCode
UA_OpenSSL_EdDSA_Ed25519_Sign(const UA_ByteString *message,
                              EVP_PKEY *privateKey,
                              UA_ByteString *outSignature);

UA_StatusCode
UA_OpenSSL_EdDSA_Ed25519_Verify(const UA_ByteString *message,
                                X509 *publicKeyX509,
                                const UA_ByteString *signature);

/* X25519/X448 key generation */
UA_StatusCode
UA_OpenSSL_X25519_GenerateKey(EVP_PKEY **keyPairOut,
                              UA_ByteString *keyPublicEncOut);

/* X25519/X448 ECDH key agreement and HKDF key derivation */
UA_StatusCode
UA_OpenSSL_XDHE_DeriveKeys(int keyType,
                            const char *hashAlgorithm,
                            UA_ApplicationType applicationType,
                            EVP_PKEY *localEphemeralKeyPair,
                            const UA_ByteString *key1,
                            const UA_ByteString *key2,
                            UA_ByteString *out);

/* ChaCha20-Poly1305 AEAD encrypt/decrypt.
 * If encryptData/decryptData is true, the data part is encrypted or decrypted.
 * Otherwise, only the authentication tag is computed/verified. */
UA_StatusCode
UA_OpenSSL_ChaCha20Poly1305_Encrypt(const UA_ByteString *iv,
                                    const UA_ByteString *key,
                                    const UA_ByteString *aad,
                                    UA_ByteString *data,
                                    UA_Boolean encryptData);

UA_StatusCode
UA_OpenSSL_ChaCha20Poly1305_Decrypt(const UA_ByteString *iv,
                                    const UA_ByteString *key,
                                    const UA_ByteString *aad,
                                    UA_ByteString *data,
                                    UA_Boolean decryptData);

/* AES-128-GCM AEAD encrypt/decrypt.
 * If encryptData/decryptData is true, the data part is encrypted or decrypted.
 * Otherwise, only the authentication tag is computed/verified. */
UA_StatusCode
UA_OpenSSL_AES_128_GCM_Encrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               const UA_ByteString *aad,
                               UA_ByteString *data,
                               UA_Boolean encryptData);

UA_StatusCode
UA_OpenSSL_AES_128_GCM_Decrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               const UA_ByteString *aad,
                               UA_ByteString *data,
                               UA_Boolean decryptData);


/* EdDSA Ed448 signing and verification */
UA_StatusCode
UA_OpenSSL_EdDSA_Ed448_Sign(const UA_ByteString *message,
                            EVP_PKEY *privateKey,
                            UA_ByteString *outSignature);

UA_StatusCode
UA_OpenSSL_EdDSA_Ed448_Verify(const UA_ByteString *message,
                              X509 *publicKeyX509,
                              const UA_ByteString *signature);

/* X448 key generation */
UA_StatusCode
UA_OpenSSL_X448_GenerateKey(EVP_PKEY **keyPairOut,
                            UA_ByteString *keyPublicEncOut);


_UA_END_DECLS

#endif /* defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) */


/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_common.h" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */



#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)

#include <mbedtls/md.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/x509_csr.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ecp.h>

// MBEDTLS_ENTROPY_HARDWARE_ALT should be defined if your hardware does not supportd platform entropy

#define UA_SHA1_LENGTH 20
#define UA_MAXSUBJECTLENGTH 512
#define MBEDTLS_SAN_MAX_LEN    64

/* 
 * Define fallback for MBEDTLS_ASN1_CHK_CLEANUP_ADD if not already defined.
 * Some versions of mbedTLS (≥3.x) provide this macro via <mbedtls/asn1write.h>,
 * but it may be missing in others, or unavailable in amalgamation builds.
 *
 * This guard ensures compatibility across mbedTLS versions without redefining
 * an existing macro, avoiding compiler warnings in UA_ENABLE_AMALGAMATION mode.
 */
#ifndef MBEDTLS_ASN1_CHK_CLEANUP_ADD
#define MBEDTLS_ASN1_CHK_CLEANUP_ADD(g, f)                    \
    do {                                                      \
        if ((ret = (f)) < 0)                                  \
            goto cleanup;                                     \
        else                                                  \
            (g) += ret;                                       \
    } while (0)
#endif

_UA_BEGIN_DECLS

#if MBEDTLS_VERSION_NUMBER < 0x02170000
#define MBEDTLS_X509_SAN_OTHER_NAME                      0
#define MBEDTLS_X509_SAN_RFC822_NAME                     1
#define MBEDTLS_X509_SAN_DNS_NAME                        2
#define MBEDTLS_X509_SAN_X400_ADDRESS_NAME               3
#define MBEDTLS_X509_SAN_DIRECTORY_NAME                  4
#define MBEDTLS_X509_SAN_EDI_PARTY_NAME                  5
#define MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER     6
#define MBEDTLS_X509_SAN_IP_ADDRESS                      7
#define MBEDTLS_X509_SAN_REGISTERED_ID                   8
#endif

void
swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB);

UA_StatusCode
mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key,
             const UA_ByteString *in, unsigned char *out);

UA_StatusCode
mbedtls_generateKey(mbedtls_md_context_t *context,
                    const UA_ByteString *secret, const UA_ByteString *seed,
                    UA_ByteString *out);

UA_StatusCode
mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message,
                       const UA_ByteString *signature);

UA_StatusCode
mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey,
                  mbedtls_ctr_drbg_context *drbgContext,
                  const UA_ByteString *message,
                  UA_ByteString *signature);

UA_StatusCode
mbedtls_thumbprint_sha1(const UA_ByteString *certificate,
                        UA_ByteString *thumbprint);

/* Set the hashing scheme before calling
 * E.g. mbedtls_rsa_set_padding(context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); */
UA_StatusCode
mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, const size_t plainTextBlockSize);

UA_StatusCode
mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, int hash_id);

UA_StatusCode
mbedtls_createSigningRequest(mbedtls_pk_context *localPrivateKey,
                             mbedtls_pk_context *csrLocalPrivateKey,
                             mbedtls_entropy_context *entropyContext,
                             mbedtls_ctr_drbg_context *drbgContext,
                             UA_SecurityPolicy *securityPolicy,
                             const UA_String *subjectName,
                             const UA_ByteString *nonce,
                             UA_ByteString *csr,
                             UA_ByteString *newPrivateKey);

int UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target, void *p_rng);

UA_StatusCode
UA_mbedTLS_LoadCertificate(const UA_ByteString *certificate, mbedtls_x509_crt *target);

UA_StatusCode
UA_mbedTLS_LoadDerCertificate(const UA_ByteString *certificate, mbedtls_x509_crt *target);

UA_StatusCode
UA_mbedTLS_LoadPemCertificate(const UA_ByteString *certificate, mbedtls_x509_crt *target);

UA_StatusCode
UA_mbedTLS_LoadCrl(const UA_ByteString *crl, mbedtls_x509_crl *target);

UA_StatusCode
UA_mbedTLS_LoadDerCrl(const UA_ByteString *crl, mbedtls_x509_crl *target);

UA_StatusCode
UA_mbedTLS_LoadPemCrl(const UA_ByteString *crl, mbedtls_x509_crl *target);

UA_StatusCode UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData, UA_ByteString *target);

UA_ByteString UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data);

#if MBEDTLS_VERSION_NUMBER >= 0x03000000

/* ECC key generation per curve */
UA_StatusCode
UA_mbedTLS_ECC_NISTP256_GenerateKey(mbedtls_pk_context *keyPairOut,
                                    mbedtls_ctr_drbg_context *drbgContext,
                                    UA_ByteString *keyPublicEncOut);

UA_StatusCode
UA_mbedTLS_ECC_NISTP384_GenerateKey(mbedtls_pk_context *keyPairOut,
                                    mbedtls_ctr_drbg_context *drbgContext,
                                    UA_ByteString *keyPublicEncOut);

UA_StatusCode
UA_mbedTLS_ECC_BRAINPOOLP256R1_GenerateKey(mbedtls_pk_context *keyPairOut,
                                           mbedtls_ctr_drbg_context *drbgContext,
                                           UA_ByteString *keyPublicEncOut);

UA_StatusCode
UA_mbedTLS_ECC_BRAINPOOLP384R1_GenerateKey(mbedtls_pk_context *keyPairOut,
                                           mbedtls_ctr_drbg_context *drbgContext,
                                           UA_ByteString *keyPublicEncOut);

/* ECC key derivation (ECDH + HKDF) */
UA_StatusCode
UA_mbedTLS_ECC_DeriveKeys(mbedtls_ecp_group_id curveID,
                          mbedtls_md_type_t hashType,
                          const UA_ApplicationType applicationType,
                          mbedtls_pk_context *localEphemeralKeyPair,
                          mbedtls_ctr_drbg_context *drbgContext,
                          const UA_ByteString *key1,
                          const UA_ByteString *key2,
                          UA_ByteString *out);

/* ECDSA signing/verification */
UA_StatusCode
UA_mbedTLS_ECDSA_SHA256_Sign(const UA_ByteString *message,
                             mbedtls_pk_context *privateKey,
                             mbedtls_ctr_drbg_context *drbgContext,
                             UA_ByteString *outSignature);

UA_StatusCode
UA_mbedTLS_ECDSA_SHA256_Verify(const UA_ByteString *message,
                               mbedtls_x509_crt *publicKeyCert,
                               const UA_ByteString *signature);

UA_StatusCode
UA_mbedTLS_ECDSA_SHA384_Sign(const UA_ByteString *message,
                             mbedtls_pk_context *privateKey,
                             mbedtls_ctr_drbg_context *drbgContext,
                             UA_ByteString *outSignature);

UA_StatusCode
UA_mbedTLS_ECDSA_SHA384_Verify(const UA_ByteString *message,
                               mbedtls_x509_crt *publicKeyCert,
                               const UA_ByteString *signature);

/* HMAC-SHA256 signing/verification (already existing for RSA policies but
 * re-exported here for ECC usage) */
UA_StatusCode
UA_mbedTLS_HMAC_SHA256_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature);

UA_StatusCode
UA_mbedTLS_HMAC_SHA256_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature);

/* HMAC-SHA384 signing/verification */
UA_StatusCode
UA_mbedTLS_HMAC_SHA384_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature);

UA_StatusCode
UA_mbedTLS_HMAC_SHA384_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature);

#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 */

_UA_END_DECLS

#endif


/**** amalgamated original file "/plugins/ua_log_stdout.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2016-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
 */


#include <stdio.h>


/* ANSI escape sequences for color output taken from here:
 * https://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c*/

#ifdef UA_ARCHITECTURE_POSIX
# define ANSI_COLOR_RED     "\x1b[31m"
# define ANSI_COLOR_GREEN   "\x1b[32m"
# define ANSI_COLOR_YELLOW  "\x1b[33m"
/* # define ANSI_COLOR_BLUE    "\x1b[34m" */
# define ANSI_COLOR_MAGENTA "\x1b[35m"
/* # define ANSI_COLOR_CYAN    "\x1b[36m" */
# define ANSI_COLOR_RESET   "\x1b[0m"
#else
# define ANSI_COLOR_RED     ""
# define ANSI_COLOR_GREEN   ""
# define ANSI_COLOR_YELLOW  ""
/* # define ANSI_COLOR_BLUE    "" */
# define ANSI_COLOR_MAGENTA ""
/* # define ANSI_COLOR_CYAN    "" */
# define ANSI_COLOR_RESET   ""
#endif

static
const char *logLevelNames[6] = {"trace", "debug",
                                ANSI_COLOR_GREEN "info",
                                ANSI_COLOR_YELLOW "warn",
                                ANSI_COLOR_RED "error",
                                ANSI_COLOR_MAGENTA "fatal"};
static const char *
logCategoryNames[UA_LOGCATEGORIES] =
    {"network", "channel", "session", "server", "client",
     "application", "security", "eventloop", "pubsub", "discovery"};

/* Protect crosstalk during logging via global lock. Use a spinlock as we cannot
 * statically initialize a global lock across all platforms. */
#if UA_MULTITHREADING >= 100
static void *logSpinLock = NULL;
static UA_INLINE void spinLock(void) {
    while(UA_atomic_cmpxchg(&logSpinLock, NULL, (void*)0x1) != NULL) {}
}
static UA_INLINE void spinUnLock(void) {
    UA_atomic_xchg(&logSpinLock, NULL);
}
#endif

#ifdef __clang__
__attribute__((__format__(__printf__, 4 , 0)))
#endif
static void
UA_Log_Stdout_log(void *context, UA_LogLevel level, UA_LogCategory category,
                  const char *msg, va_list args) {
    /* MinLevel encoded in the context pointer */
    UA_LogLevel minLevel = (UA_LogLevel)(uintptr_t)context;
    if(minLevel > level)
        return;

    UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset();
    UA_DateTimeStruct dts = UA_DateTime_toStruct(UA_DateTime_now() + tOffset);

    int logLevelSlot = ((int)level / 100) - 1;
    if(logLevelSlot < 0 || logLevelSlot > 5)
        logLevelSlot = 5; /* Set to fatal if the level is outside the range */

    /* Lock */
#if UA_MULTITHREADING >= 100
    spinLock();
#endif

#define STDOUT_LOGBUFSIZE 512
    char logbuf[STDOUT_LOGBUFSIZE];

    /* Log */
    printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t",
           dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec,
           (int)(tOffset / UA_DATETIME_SEC / 36), logLevelNames[logLevelSlot],
           logCategoryNames[category]);
    mp_vsnprintf(logbuf, STDOUT_LOGBUFSIZE, msg, args);
    printf("%s\n", logbuf);
    fflush(stdout);

    /* Unlock */
#if UA_MULTITHREADING >= 100
    spinUnLock();
#endif
}

static void
UA_Log_Stdout_clear(UA_Logger *logger) {
    UA_free(logger);
}

const UA_Logger UA_Log_Stdout_ = {UA_Log_Stdout_log, NULL, NULL};
const UA_Logger *UA_Log_Stdout = &UA_Log_Stdout_;

UA_Logger
UA_Log_Stdout_withLevel(UA_LogLevel minlevel) {
    UA_Logger logger =
        {UA_Log_Stdout_log, (void*)(uintptr_t)minlevel, NULL};
    return logger;
}

UA_Logger *
UA_Log_Stdout_new(UA_LogLevel minlevel) {
    UA_Logger *logger = (UA_Logger*)UA_malloc(sizeof(UA_Logger));
    if(!logger)
        return NULL;
    *logger = UA_Log_Stdout_withLevel(minlevel);
    logger->clear = UA_Log_Stdout_clear;
    return logger;
}

/**** amalgamated original file "/plugins/ua_accesscontrol_default.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */


/* Example access control management. Anonymous and username / password login.
 * The access rights are maximally permissive.
 *
 * FOR PRODUCTION USE, THIS EXAMPLE PLUGIN SHOULD BE REPLACED WITH LESS
 * PERMISSIVE ACCESS CONTROL.
 *
 * For TransferSubscriptions, we check whether the transfer happens between
 * Sessions for the same user. */

typedef struct {
    UA_Boolean allowAnonymous;
    size_t usernamePasswordLoginSize;
    UA_UsernamePasswordLogin *usernamePasswordLogin;
    UA_UsernamePasswordLoginCallback loginCallback;
    void *loginContext;
    UA_CertificateGroup verifyX509;
} AccessControlContext;

#define ANONYMOUS_POLICY "open62541-anonymous-policy"
#define CERTIFICATE_POLICY "open62541-certificate-policy"
#define USERNAME_POLICY "open62541-username-policy"

/************************/
/* Access Control Logic */
/************************/

static UA_StatusCode
activateSession_default(UA_Server *server, UA_AccessControl *ac,
                        const UA_EndpointDescription *endpointDescription,
                        const UA_ByteString *secureChannelRemoteCertificate,
                        const UA_NodeId *sessionId,
                        const UA_ExtensionObject *userIdentityToken,
                        void **sessionContext) {
    AccessControlContext *context = (AccessControlContext*)ac->context;

    /* The empty token is interpreted as anonymous */
    UA_AnonymousIdentityToken anonToken;
    UA_ExtensionObject tmpIdentity;
    if(userIdentityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
        UA_AnonymousIdentityToken_init(&anonToken);
        UA_ExtensionObject_init(&tmpIdentity);
        UA_ExtensionObject_setValueNoDelete(&tmpIdentity,
                                            &anonToken,
                                            &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]);
        userIdentityToken = &tmpIdentity;
    }

    /* Could the token be decoded? */
    if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED)
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

    const UA_DataType *tokenType = userIdentityToken->content.decoded.type;
    if(tokenType == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
        /* Anonymous login */
        if(!context->allowAnonymous)
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
    } else if(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
        /* Username and password */
        const UA_UserNameIdentityToken *userToken = (UA_UserNameIdentityToken*)
            userIdentityToken->content.decoded.data;

        /* Empty username and password */
        if(userToken->userName.length == 0 && userToken->password.length == 0)
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

        /* Try to match username/pw */
        if(context->loginCallback) {
            /* Configured callback */
            UA_StatusCode res =
                context->loginCallback(&userToken->userName, &userToken->password,
                                       context->usernamePasswordLoginSize,
                                       context->usernamePasswordLogin,
                                       sessionContext, context->loginContext);
            if(res != UA_STATUSCODE_GOOD)
                return UA_STATUSCODE_BADUSERACCESSDENIED;
        } else {
            /* Compare against the configured list  */
            UA_Boolean match = false;
            for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
                UA_UsernamePasswordLogin *upl = &context->usernamePasswordLogin[i];
                if(!UA_String_equal(&userToken->userName, &upl->username))
                   continue;
                if(userToken->password.length != upl->password.length)
                    continue;
                if(!UA_constantTimeEqual(userToken->password.data,
                                         upl->password.data,
                                         upl->password.length))
                    continue;
                match = true;
                break;
            }
            if(!match)
                return UA_STATUSCODE_BADUSERACCESSDENIED;
        }
    } else if(tokenType == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) {
        /* x509 certificate was already validated against the sessionPKI in the
         * server */
    } else {
        /* Unsupported token type */
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
    }

    /* Store the endpoint's SecurityPolicyUri as a custom session attribute.
     * This is needed later in allowTransferSubscription_default to determine
     * whether the session was established over a secure channel. */
    if(endpointDescription) {
        UA_Variant spUri;
        UA_Variant_setScalar(&spUri, (void*)(uintptr_t)&endpointDescription->securityPolicyUri,
                             &UA_TYPES[UA_TYPES_STRING]);
        UA_Server_setSessionAttribute(server, sessionId,
                                      UA_QUALIFIEDNAME(0, "channelSecurityPolicyUri"),
                                      &spUri);
    }

    return UA_STATUSCODE_GOOD;
}

static void
closeSession_default(UA_Server *server, UA_AccessControl *ac,
                     const UA_NodeId *sessionId, void *sessionContext) {
}

static UA_UInt32
getUserRightsMask_default(UA_Server *server, UA_AccessControl *ac,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *nodeId, void *nodeContext) {
    return 0xFFFFFFFF;
}

static UA_Byte
getUserAccessLevel_default(UA_Server *server, UA_AccessControl *ac,
                           const UA_NodeId *sessionId, void *sessionContext,
                           const UA_NodeId *nodeId, void *nodeContext) {
    return 0xFF;
}

static UA_Boolean
getUserExecutable_default(UA_Server *server, UA_AccessControl *ac,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext) {
    return true;
}

static UA_Boolean
getUserExecutableOnObject_default(UA_Server *server, UA_AccessControl *ac,
                                  const UA_NodeId *sessionId, void *sessionContext,
                                  const UA_NodeId *methodId, void *methodContext,
                                  const UA_NodeId *objectId, void *objectContext) {
    return true;
}

static UA_Boolean
allowAddNode_default(UA_Server *server, UA_AccessControl *ac,
                     const UA_NodeId *sessionId, void *sessionContext,
                     const UA_AddNodesItem *item) {
    return true;
}

static UA_Boolean
allowAddReference_default(UA_Server *server, UA_AccessControl *ac,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_AddReferencesItem *item) {
    return true;
}

static UA_Boolean
allowDeleteNode_default(UA_Server *server, UA_AccessControl *ac,
                        const UA_NodeId *sessionId, void *sessionContext,
                        const UA_DeleteNodesItem *item) {
    return true;
}

static UA_Boolean
allowDeleteReference_default(UA_Server *server, UA_AccessControl *ac,
                             const UA_NodeId *sessionId, void *sessionContext,
                             const UA_DeleteReferencesItem *item) {
    return true;
}

static UA_Boolean
allowBrowseNode_default(UA_Server *server, UA_AccessControl *ac,
                        const UA_NodeId *sessionId, void *sessionContext,
                        const UA_NodeId *nodeId, void *nodeContext) {
    return true;
}

#ifdef UA_ENABLE_SUBSCRIPTIONS
static UA_Boolean
allowTransferSubscription_default(UA_Server *server, UA_AccessControl *ac,
                                  const UA_NodeId *oldSessionId, void *oldSessionContext,
                                  const UA_NodeId *newSessionId, void *newSessionContext) {
    if(!oldSessionId)
        return false;
    
    /* Get clientUserId for both sessions */
    UA_Variant session1UserId;
    UA_Variant_init(&session1UserId);
    UA_Server_getSessionAttribute(server, oldSessionId,
                                  UA_QUALIFIEDNAME(0, "clientUserId"),
                                  &session1UserId);
    UA_Variant session2UserId;
    UA_Variant_init(&session2UserId);
    UA_Server_getSessionAttribute(server, newSessionId,
                                  UA_QUALIFIEDNAME(0, "clientUserId"),
                                  &session2UserId);

    /* clientUserId is always a String type */
    UA_Boolean result = false;
    if(session1UserId.type == &UA_TYPES[UA_TYPES_STRING] &&
       session2UserId.type == &UA_TYPES[UA_TYPES_STRING]) {
        UA_String *userId1 = (UA_String*)session1UserId.data;
        UA_String *userId2 = (UA_String*)session2UserId.data;
        
        if(userId1->length == 0 && userId2->length == 0) {
            /* Both users are anonymous.
             * For anonymous users, the OPC UA specification requires
             * checking the ApplicationUri from the clientDescription
             * to verify that the same application is transferring the
             * subscription (e.g. after a network interruption or client
             * crash with reconnect on a different SecureChannel).
             *
             * Additionally, on unsecure connections (SecurityPolicy#None)
             * the ApplicationUri is not verified against a certificate,
             * so the transfer must be rejected. */

            /* First check: Both sessions must use a secure channel
             * (not SecurityPolicy#None). The securityPolicyUri was
             * stored as a session attribute during ActivateSession. */
            UA_Variant session1SpUri;
            UA_Variant_init(&session1SpUri);
            UA_Server_getSessionAttribute(server, oldSessionId,
                                          UA_QUALIFIEDNAME(0, "channelSecurityPolicyUri"),
                                          &session1SpUri);
            UA_Variant session2SpUri;
            UA_Variant_init(&session2SpUri);
            UA_Server_getSessionAttribute(server, newSessionId,
                                          UA_QUALIFIEDNAME(0, "channelSecurityPolicyUri"),
                                          &session2SpUri);

            UA_Boolean bothSecure = false;
            if(session1SpUri.type == &UA_TYPES[UA_TYPES_STRING] &&
               session2SpUri.type == &UA_TYPES[UA_TYPES_STRING]) {
                UA_String *spUri1 = (UA_String*)session1SpUri.data;
                UA_String *spUri2 = (UA_String*)session2SpUri.data;
                /* Reject if either session uses SecurityPolicy#None */
                if(!UA_String_equal(spUri1, &UA_SECURITY_POLICY_NONE_URI) &&
                   !UA_String_equal(spUri2, &UA_SECURITY_POLICY_NONE_URI)) {
                    bothSecure = true;
                }
            }

            UA_Variant_clear(&session1SpUri);
            UA_Variant_clear(&session2SpUri);

            /* Second check: If both channels are secure, compare the
             * ApplicationUri from the clientDescription. On secure
             * connections the ApplicationUri is validated against
             * the client certificate during CreateSession. */
            if(bothSecure) {
                UA_Variant session1Desc;
                UA_Variant_init(&session1Desc);
                UA_Server_getSessionAttribute(server, oldSessionId,
                                              UA_QUALIFIEDNAME(0, "clientDescription"),
                                              &session1Desc);
                UA_Variant session2Desc;
                UA_Variant_init(&session2Desc);
                UA_Server_getSessionAttribute(server, newSessionId,
                                              UA_QUALIFIEDNAME(0, "clientDescription"),
                                              &session2Desc);

                if(session1Desc.type == &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION] &&
                   session2Desc.type == &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]) {
                    UA_ApplicationDescription *desc1 =
                        (UA_ApplicationDescription*)session1Desc.data;
                    UA_ApplicationDescription *desc2 =
                        (UA_ApplicationDescription*)session2Desc.data;
                    if(desc1->applicationUri.length > 0 &&
                       desc2->applicationUri.length > 0 &&
                       UA_String_equal(&desc1->applicationUri,
                                       &desc2->applicationUri)) {
                        result = true;
                    }
                }

                UA_Variant_clear(&session1Desc);
                UA_Variant_clear(&session2Desc);
            }
        } else if(UA_String_equal(userId1, userId2)) {
            /* Same authenticated user - allow transfer */
            result = true;
        }
    }
    
    UA_Variant_clear(&session1UserId);
    UA_Variant_clear(&session2UserId);
    
    return result;
}
#endif

#ifdef UA_ENABLE_HISTORIZING
static UA_Boolean
allowHistoryUpdateUpdateData_default(UA_Server *server, UA_AccessControl *ac,
                                     const UA_NodeId *sessionId, void *sessionContext,
                                     const UA_NodeId *nodeId,
                                     UA_PerformUpdateType performInsertReplace,
                                     const UA_DataValue *value) {
    return true;
}

static UA_Boolean
allowHistoryUpdateDeleteRawModified_default(UA_Server *server, UA_AccessControl *ac,
                                            const UA_NodeId *sessionId, void *sessionContext,
                                            const UA_NodeId *nodeId,
                                            UA_DateTime startTimestamp,
                                            UA_DateTime endTimestamp,
                                            bool isDeleteModified) {
    return true;
}
#endif

/***************************************/
/* Create Delete Access Control Plugin */
/***************************************/

static void clear_default(UA_AccessControl *ac) {
    UA_Array_delete((void*)(uintptr_t)ac->userTokenPolicies,
                    ac->userTokenPoliciesSize,
                    &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
    ac->userTokenPolicies = NULL;
    ac->userTokenPoliciesSize = 0;

    AccessControlContext *context = (AccessControlContext*)ac->context;

    if (context) {
        for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
            UA_String_clear(&context->usernamePasswordLogin[i].username);
            UA_ByteString_clear(&context->usernamePasswordLogin[i].password);
        }
        if(context->usernamePasswordLoginSize > 0)
            UA_free(context->usernamePasswordLogin);

        UA_free(ac->context);
        ac->context = NULL;
    }
}

UA_StatusCode
UA_AccessControl_default(UA_ServerConfig *config,
                         UA_Boolean allowAnonymous,
                         const UA_String *userTokenPolicyUri,
                         size_t usernamePasswordLoginSize,
                         const UA_UsernamePasswordLogin *usernamePasswordLogin) {
    UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                   "AccessControl: Unconfigured AccessControl. Users have all permissions.");
    UA_AccessControl *ac = &config->accessControl;

    if(ac->clear)
        ac->clear(ac);

    ac->clear = clear_default;
    ac->activateSession = activateSession_default;
    ac->closeSession = closeSession_default;
    ac->getUserRightsMask = getUserRightsMask_default;
    ac->getUserAccessLevel = getUserAccessLevel_default;
    ac->getUserExecutable = getUserExecutable_default;
    ac->getUserExecutableOnObject = getUserExecutableOnObject_default;
    ac->allowAddNode = allowAddNode_default;
    ac->allowAddReference = allowAddReference_default;
    ac->allowBrowseNode = allowBrowseNode_default;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    ac->allowTransferSubscription = allowTransferSubscription_default;
#endif

#ifdef UA_ENABLE_HISTORIZING
    ac->allowHistoryUpdateUpdateData = allowHistoryUpdateUpdateData_default;
    ac->allowHistoryUpdateDeleteRawModified = allowHistoryUpdateDeleteRawModified_default;
#endif

    ac->allowDeleteNode = allowDeleteNode_default;
    ac->allowDeleteReference = allowDeleteReference_default;

    AccessControlContext *context = (AccessControlContext*)
            UA_malloc(sizeof(AccessControlContext));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(context, 0, sizeof(AccessControlContext));
    ac->context = context;

    /* Allow anonymous? */
    context->allowAnonymous = allowAnonymous;
    if(allowAnonymous) {
        UA_LOG_INFO(config->logging, UA_LOGCATEGORY_SERVER,
                    "AccessControl: Anonymous login is enabled");
    }

    /* Copy username/password to the access control plugin */
    if(usernamePasswordLoginSize > 0) {
        context->usernamePasswordLogin = (UA_UsernamePasswordLogin*)
            UA_malloc(usernamePasswordLoginSize * sizeof(UA_UsernamePasswordLogin));
        if(!context->usernamePasswordLogin)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        context->usernamePasswordLoginSize = usernamePasswordLoginSize;
        for(size_t i = 0; i < usernamePasswordLoginSize; i++) {
            UA_String_copy(&usernamePasswordLogin[i].username,
                           &context->usernamePasswordLogin[i].username);
            UA_ByteString_copy(&usernamePasswordLogin[i].password,
                           &context->usernamePasswordLogin[i].password);
        }
    }

    size_t numOfPolcies = 1;
    if(!userTokenPolicyUri) {
        if(config->securityPoliciesSize > 0)
            numOfPolcies = config->securityPoliciesSize;
        else {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                           "No security policies defined for the secure channel.");
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    /* Set the allowed policies */
    size_t policies = 0;
    if(allowAnonymous)
        policies++;
    if(usernamePasswordLoginSize > 0)
        policies++;
    if(config->sessionPKI.verifyCertificate)
        policies++;
    ac->userTokenPoliciesSize = 0;
    ac->userTokenPolicies = (UA_UserTokenPolicy *)
        UA_Array_new(policies * numOfPolcies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
    if(!ac->userTokenPolicies)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    ac->userTokenPoliciesSize = policies * numOfPolcies;

    if(policies == 0) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "No allowed policies set.");
        return UA_STATUSCODE_GOOD;
    }

    const UA_String *utpUri = NULL;
    policies = 0;
    for(size_t i = 0; i < numOfPolcies; i++) {
        if(userTokenPolicyUri) {
            utpUri = userTokenPolicyUri;
        } else {
            utpUri = &config->securityPolicies[i].policyUri;
        }
        if(allowAnonymous) {
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY);
            UA_String_copy(utpUri,
                               &ac->userTokenPolicies[policies].securityPolicyUri);
            policies++;
        }

        if(config->sessionPKI.verifyCertificate) {
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_CERTIFICATE;
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(CERTIFICATE_POLICY);
#if UA_LOGLEVEL <= 400
            if(UA_String_equal(utpUri, &UA_SECURITY_POLICY_NONE_URI)) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                               "x509 Certificate Authentication configured, "
                               "but no encrypting SecurityPolicy. "
                               "This can leak credentials on the network.");
            }
#endif
            UA_String_copy(utpUri,
                               &ac->userTokenPolicies[policies].securityPolicyUri);
            policies++;
        }

        if(usernamePasswordLoginSize > 0) {
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME;
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
#if UA_LOGLEVEL <= 400
            if(UA_String_equal(utpUri, &UA_SECURITY_POLICY_NONE_URI)) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                               "Username/Password Authentication configured, "
                               "but no encrypting SecurityPolicy. "
                               "This can leak credentials on the network.");
            }
#endif
            UA_String_copy(utpUri,
                               &ac->userTokenPolicies[policies].securityPolicyUri);
            policies++;
        }
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_AccessControl_defaultWithLoginCallback(UA_ServerConfig *config,
                                          UA_Boolean allowAnonymous,
                                          const UA_String *userTokenPolicyUri,
                                          size_t usernamePasswordLoginSize,
                                          const UA_UsernamePasswordLogin *usernamePasswordLogin,
                                          UA_UsernamePasswordLoginCallback loginCallback,
                                          void *loginContext) {
    AccessControlContext *context;
    UA_StatusCode sc =
        UA_AccessControl_default(config, allowAnonymous, userTokenPolicyUri,
                                 usernamePasswordLoginSize, usernamePasswordLogin);
    if(sc != UA_STATUSCODE_GOOD)
        return sc;

    context = (AccessControlContext *)config->accessControl.context;
    context->loginCallback = loginCallback;
    context->loginContext = loginContext;

    return UA_STATUSCODE_GOOD;
}


/**** amalgamated original file "/plugins/ua_nodestore_ziptree.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


#ifndef container_of
#define container_of(ptr, type, member) \
    (type *)((uintptr_t)ptr - offsetof(type,member))
#endif

struct NodeEntry;
typedef struct NodeEntry NodeEntry;

struct NodeEntry {
    ZIP_ENTRY(NodeEntry) zipfields;
    UA_UInt32 nodeIdHash;
    UA_UInt16 refCount; /* How many consumers have a reference to the node? */
    UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */
    NodeEntry *orig;    /* If a copy is made to replace a node, track that we
                         * replace only the node from which the copy was made.
                         * Important for concurrent operations. */
    UA_NodeId nodeId; /* This is actually a UA_Node that also starts with a NodeId */
};

/* Absolute ordering for NodeIds */
static enum ZIP_CMP
cmpNodeId(const void *a, const void *b) {
    const NodeEntry *aa = (const NodeEntry*)a;
    const NodeEntry *bb = (const NodeEntry*)b;

    /* Compare hash */
    if(aa->nodeIdHash < bb->nodeIdHash)
        return ZIP_CMP_LESS;
    if(aa->nodeIdHash > bb->nodeIdHash)
        return ZIP_CMP_MORE;

    /* Compore nodes in detail */
    return (enum ZIP_CMP)UA_NodeId_order(&aa->nodeId, &bb->nodeId);
}

ZIP_HEAD(NodeTree, NodeEntry);
typedef struct NodeTree NodeTree;

typedef struct {
    UA_Nodestore ns;

    NodeTree root;
    size_t size;

    /* Maps ReferenceTypeIndex to the NodeId of the ReferenceType */
    UA_NodeId referenceTypeIds[UA_REFERENCETYPESET_MAX];
    UA_Byte referenceTypeCounter;
} ZipNodestore;

ZIP_FUNCTIONS(NodeTree, NodeEntry, zipfields, NodeEntry, zipfields, cmpNodeId)

static NodeEntry *
newEntry(UA_NodeClass nodeClass) {
    size_t size = sizeof(NodeEntry) - sizeof(UA_NodeId);
    switch(nodeClass) {
    case UA_NODECLASS_OBJECT:
        size += sizeof(UA_ObjectNode);
        break;
    case UA_NODECLASS_VARIABLE:
        size += sizeof(UA_VariableNode);
        break;
    case UA_NODECLASS_METHOD:
        size += sizeof(UA_MethodNode);
        break;
    case UA_NODECLASS_OBJECTTYPE:
        size += sizeof(UA_ObjectTypeNode);
        break;
    case UA_NODECLASS_VARIABLETYPE:
        size += sizeof(UA_VariableTypeNode);
        break;
    case UA_NODECLASS_REFERENCETYPE:
        size += sizeof(UA_ReferenceTypeNode);
        break;
    case UA_NODECLASS_DATATYPE:
        size += sizeof(UA_DataTypeNode);
        break;
    case UA_NODECLASS_VIEW:
        size += sizeof(UA_ViewNode);
        break;
    default:
        return NULL;
    }
    NodeEntry *entry = (NodeEntry*)UA_calloc(1, size);
    if(!entry)
        return NULL;
    UA_Node *node = (UA_Node*)&entry->nodeId;
    node->head.nodeClass = nodeClass;
    return entry;
}

static void
deleteEntry(NodeEntry *entry) {
    UA_Node_clear((UA_Node*)&entry->nodeId);
    UA_free(entry);
}

static void
cleanupEntry(NodeEntry *entry) {
    if(entry->refCount > 0)
        return;
    if(entry->deleted) {
        deleteEntry(entry);
        return;
    }
    UA_NodeHead *head = (UA_NodeHead*)&entry->nodeId;
    for(size_t i = 0; i < head->referencesSize; i++) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(rk->targetsSize > 16 && !rk->hasRefTree)
            UA_NodeReferenceKind_switch(rk);
    }
}

/***********************/
/* Interface functions */
/***********************/

/* Not yet inserted into the ZipContext */
static UA_Node *
zipNsNewNode(UA_Nodestore *_, UA_NodeClass nodeClass) {
    NodeEntry *entry = newEntry(nodeClass);
    if(!entry)
        return NULL;
    return (UA_Node*)&entry->nodeId;
}

/* Not yet inserted into the ZipContext */
static void
zipNsDeleteNode(UA_Nodestore *_, UA_Node *node) {
    deleteEntry(container_of(node, NodeEntry, nodeId));
}

static const UA_Node *
zipNsGetNode(UA_Nodestore *ns, const UA_NodeId *nodeId,
             UA_UInt32 attributeMask,
             UA_ReferenceTypeSet references,
             UA_BrowseDirection referenceDirections) {
    NodeEntry dummy;
    dummy.nodeIdHash = UA_NodeId_hash(nodeId);
    dummy.nodeId = *nodeId;
    ZipNodestore *zns = (ZipNodestore*)ns;
    NodeEntry *entry = ZIP_FIND(NodeTree, &zns->root, &dummy);
    if(!entry)
        return NULL;
    ++entry->refCount;
    return (const UA_Node*)&entry->nodeId;
}

static const UA_Node *
zipNsGetNodeFromPtr(UA_Nodestore *ns, UA_NodePointer ptr,
                    UA_UInt32 attributeMask,
                    UA_ReferenceTypeSet references,
                    UA_BrowseDirection referenceDirections) {
    if(!UA_NodePointer_isLocal(ptr))
        return NULL;
    UA_NodeId id = UA_NodePointer_toNodeId(ptr);
    return zipNsGetNode(ns, &id, attributeMask,
                        references, referenceDirections);
}

static void
zipNsReleaseNode(UA_Nodestore *_, const UA_Node *node) {
    if(!node)
        return;
    NodeEntry *entry = container_of(node, NodeEntry, nodeId);
    UA_assert(entry->refCount > 0);
    --entry->refCount;
    cleanupEntry(entry);
}

static UA_StatusCode
zipNsGetNodeCopy(UA_Nodestore *ns, const UA_NodeId *nodeId,
                 UA_Node **outNode) {
    /* Get the node (with all attributes and references, the mask and refs are
       currently noy evaluated within the plugin.) */
    const UA_Node *node =
        zipNsGetNode(ns, nodeId, UA_NODEATTRIBUTESMASK_ALL,
                     UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* Create the new entry */
    NodeEntry *ne = newEntry(node->head.nodeClass);
    if(!ne) {
        zipNsReleaseNode(ns, node);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Copy the node content */
    UA_Node *nnode = (UA_Node*)&ne->nodeId;
    UA_StatusCode retval = UA_Node_copy(node, nnode);
    zipNsReleaseNode(NULL, node);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteEntry(ne);
        return retval;
    }

    ne->orig = container_of(node, NodeEntry, nodeId);
    *outNode = nnode;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
zipNsInsertNode(UA_Nodestore *ns, UA_Node *node, UA_NodeId *addedNodeId) {
    NodeEntry *entry = container_of(node, NodeEntry, nodeId);
    ZipNodestore *zns = (ZipNodestore*)ns;

    /* Ensure that the NodeId is unique by testing their presence. If the NodeId
     * is ns=xx;i=0, then the numeric identifier is replaced with a random
     * unused int32. It is ensured that the created identifiers are stable after
     * a server restart (assuming that Nodes are created in the same order and
     * with the same BrowseName). */
    NodeEntry dummy;
    memset(&dummy, 0, sizeof(NodeEntry));
    dummy.nodeId = node->head.nodeId;
    if(node->head.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
       node->head.nodeId.identifier.numeric == 0) {
        NodeEntry *found;
        UA_UInt32 mask = 0x2F;
        pcg32_random_t rng;
        pcg32_srandom_r(&rng, zns->size, 0);
        do {
            /* Generate a random NodeId. Favor "easy" NodeIds.
             * Always above 50000. */
            UA_UInt32 numId = (pcg32_random_r(&rng) & mask) + 50000;

#if SIZE_MAX <= UA_UINT32_MAX
            /* The compressed "immediate" representation of nodes does not
             * support the full range on 32bit systems. Generate smaller
             * identifiers as they can be stored more compactly. */
            if(numId >= (0x01 << 24))
                numId = numId % (0x01 << 24);
#endif
            node->head.nodeId.identifier.numeric = numId;

            /* Look up the current NodeId */
            dummy.nodeId.identifier.numeric = numId;
            dummy.nodeIdHash = UA_NodeId_hash(&node->head.nodeId);
            found = ZIP_FIND(NodeTree, &zns->root, &dummy);

            if(found) {
                /* Reseed the rng using the browseName of the existing node.
                 * This ensures that different information models end up with
                 * different NodeId sequences, but still stable after a
                 * restart. */
                UA_NodeHead *nh = (UA_NodeHead*)&found->nodeId;
                pcg32_srandom_r(&rng, rng.state, UA_QualifiedName_hash(&nh->browseName));

                /* Make the mask less strict when the NodeId already exists */
                mask = (mask << 1) | 0x01;
            }
        } while(found);
    } else {
        dummy.nodeIdHash = UA_NodeId_hash(&node->head.nodeId);
        if(ZIP_FIND(NodeTree, &zns->root, &dummy)) { /* The nodeid exists */
            deleteEntry(entry);
            return UA_STATUSCODE_BADNODEIDEXISTS;
        }
    }

    /* Copy the NodeId */
    if(addedNodeId) {
        UA_StatusCode retval = UA_NodeId_copy(&node->head.nodeId, addedNodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteEntry(entry);
            return retval;
        }
    }

    /* For new ReferencetypeNodes add to the index map */
    if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) {
        UA_ReferenceTypeNode *refNode = &node->referenceTypeNode;
        if(zns->referenceTypeCounter >= UA_REFERENCETYPESET_MAX) {
            deleteEntry(entry);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        UA_StatusCode retval =
            UA_NodeId_copy(&node->head.nodeId,
                           &zns->referenceTypeIds[zns->referenceTypeCounter]);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteEntry(entry);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        /* Assign the ReferenceTypeIndex to the new ReferenceTypeNode */
        refNode->referenceTypeIndex = zns->referenceTypeCounter;
        refNode->subTypes = UA_REFTYPESET(zns->referenceTypeCounter);
        zns->referenceTypeCounter++;
    }

    /* Insert the node */
    entry->nodeIdHash = dummy.nodeIdHash;
    ZIP_INSERT(NodeTree, &zns->root, entry);
    zns->size++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
zipNsReplaceNode(UA_Nodestore *ns, UA_Node *node) {
    /* Find the node (the mask and refs are not evaluated yet by the plugin)*/
    const UA_Node *oldNode =
        zipNsGetNode(ns, &node->head.nodeId, UA_NODEATTRIBUTESMASK_ALL,
                     UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
    if(!oldNode) {
        deleteEntry(container_of(node, NodeEntry, nodeId));
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    /* Test if the copy is current */
    NodeEntry *entry = container_of(node, NodeEntry, nodeId);
    NodeEntry *oldEntry = container_of(oldNode, NodeEntry, nodeId);
    if(oldEntry != entry->orig) {
        /* The node was already updated since the copy was made */
        deleteEntry(entry);
        zipNsReleaseNode(NULL, oldNode);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Replace */
    ZipNodestore *zns = (ZipNodestore*)ns;
    ZIP_REMOVE(NodeTree, &zns->root, oldEntry);
    entry->nodeIdHash = oldEntry->nodeIdHash;
    ZIP_INSERT(NodeTree, &zns->root, entry);
    oldEntry->deleted = true;

    zipNsReleaseNode(NULL, oldNode);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
zipNsRemoveNode(UA_Nodestore *ns, const UA_NodeId *nodeId) {
    ZipNodestore *zns = (ZipNodestore*)ns;
    NodeEntry dummy;
    dummy.nodeIdHash = UA_NodeId_hash(nodeId);
    dummy.nodeId = *nodeId;
    NodeEntry *entry = ZIP_FIND(NodeTree, &zns->root, &dummy);
    if(!entry)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    ZIP_REMOVE(NodeTree, &zns->root, entry);
    zns->size--;
    entry->deleted = true;
    cleanupEntry(entry);
    return UA_STATUSCODE_GOOD;
}

static const UA_NodeId *
zipNsGetReferenceTypeId(UA_Nodestore *ns, UA_Byte refTypeIndex) {
    ZipNodestore *zns = (ZipNodestore*)ns;
    if(refTypeIndex >= zns->referenceTypeCounter)
        return NULL;
    return &zns->referenceTypeIds[refTypeIndex];
}

struct VisitorData {
    UA_NodestoreVisitor visitor;
    void *visitorContext;
};

static void *
nodeVisitor(void *data, NodeEntry *entry) {
    struct VisitorData *d = (struct VisitorData*)data;
    d->visitor(d->visitorContext, (UA_Node*)&entry->nodeId);
    return NULL;
}

static void
zipNsIterate(UA_Nodestore *ns, UA_NodestoreVisitor visitor,
             void *visitorCtx) {
    struct VisitorData d;
    d.visitor = visitor;
    d.visitorContext = visitorCtx;
    ZipNodestore *zns = (ZipNodestore*)ns;
    ZIP_ITER(NodeTree, &zns->root, nodeVisitor, &d);
}

static void *
deleteNodeVisitor(void *data, NodeEntry *entry) {
    deleteEntry(entry);
    return NULL;
}

/***********************/
/* Nodestore Lifecycle */
/***********************/

static void
zipNsFree(UA_Nodestore *ns) {
    ZipNodestore *zns = (ZipNodestore*)ns;
    ZIP_ITER(NodeTree, &zns->root, deleteNodeVisitor, NULL);

    /* Clean up the ReferenceTypes index array */
    for(size_t i = 0; i < zns->referenceTypeCounter; i++)
        UA_NodeId_clear(&zns->referenceTypeIds[i]);

    UA_free(zns);
}

UA_Nodestore *
UA_Nodestore_ZipTree(void) {
    /* Allocate and initialize the context */
    ZipNodestore *zns = (ZipNodestore*)UA_calloc(1, sizeof(ZipNodestore));
    if(!zns)
        return NULL;

    ZIP_INIT(&zns->root);
    zns->referenceTypeCounter = 0;

    /* Populate the nodestore */
    zns->ns.free = zipNsFree;
    zns->ns.newNode = zipNsNewNode;
    zns->ns.deleteNode = zipNsDeleteNode;
    zns->ns.getNode = zipNsGetNode;
    zns->ns.getNodeFromPtr = zipNsGetNodeFromPtr;
    zns->ns.releaseNode = zipNsReleaseNode;
    zns->ns.getNodeCopy = zipNsGetNodeCopy;
    zns->ns.insertNode = zipNsInsertNode;
    zns->ns.replaceNode = zipNsReplaceNode;
    zns->ns.removeNode = zipNsRemoveNode;
    zns->ns.getReferenceTypeId = zipNsGetReferenceTypeId;
    zns->ns.iterate = zipNsIterate;

    /* All nodes are stored in RAM. Changes are made in-situ. GetEditNode is
     * identical to GetNode -- but the Node pointer is non-const. */
    zns->ns.getEditNode =
        (UA_Node * (*)(UA_Nodestore *ns, const UA_NodeId *nodeId,
                       UA_UInt32 attributeMask,
                       UA_ReferenceTypeSet references,
                       UA_BrowseDirection referenceDirections))zipNsGetNode;
    zns->ns.getEditNodeFromPtr =
        (UA_Node * (*)(UA_Nodestore *ns, UA_NodePointer ptr,
                       UA_UInt32 attributeMask,
                       UA_ReferenceTypeSet references,
                       UA_BrowseDirection referenceDirections))zipNsGetNodeFromPtr;

    return &zns->ns;
}

/**** amalgamated original file "/plugins/ua_config_default.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */

#if defined(UA_ENABLE_DISCOVERY) || defined(UA_ENABLE_AMALGAMATION)
#endif


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
#include <mbedtls/version.h>
#endif

#include <stdio.h>
#ifdef UA_ARCHITECTURE_WIN32
# include <winsock2.h>
#else
# include <unistd.h>
#endif

/* Struct initialization works across ANSI C/C99/C++ if it is done when the
 * variable is first declared. Assigning values to existing structs is
 * heterogeneous across the three. */
static UA_INLINE UA_UInt32Range
UA_UINT32RANGE(UA_UInt32 min, UA_UInt32 max) {
    UA_UInt32Range range = {min, max};
    return range;
}

static UA_INLINE UA_DurationRange
UA_DURATIONRANGE(UA_Duration min, UA_Duration max) {
    UA_DurationRange range = {min, max};
    return range;
}

/* Request the private key password from stdin if no callback is defined */
#ifdef UA_ENABLE_ENCRYPTION
static UA_StatusCode
readPrivateKeyPassword(UA_ByteString *password) {
    /* Read from stdin */
    char buf[256];
    fputs("Private key requires a password. Enter and press return: ", stdout);
    char *s = fgets(buf, 256, stdin);
    if(!s)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Get rid of any trailing \n */
    size_t len = strlen(buf);
    if(len == 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(buf[len-1] == '\n')
        buf[len-1] = 0;

    *password = UA_BYTESTRING_ALLOC(buf);
    return UA_STATUSCODE_GOOD;
}
#endif

UA_Server *
UA_Server_new(void) {
    UA_ServerConfig config;
    memset(&config, 0, sizeof(UA_ServerConfig));
    UA_StatusCode res = UA_ServerConfig_setDefault(&config);
    if(res != UA_STATUSCODE_GOOD)
        return NULL;
    return UA_Server_newWithConfig(&config);
}

#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) || defined(UA_ARCHITECTURE_ZEPHYR)
/* Required for the definition of SIGINT */
#include <signal.h>

struct InterruptContext {
    UA_Server *server;
    UA_Boolean running;
};

static void
shutdownServer(UA_Server *server, void *context) {
    struct InterruptContext *ic = (struct InterruptContext*)context;
    UA_ServerConfig *config = UA_Server_getConfig(ic->server);
    UA_LOG_INFO(config->logging, UA_LOGCATEGORY_APPLICATION,
                "Stopping the server");
    ic->running = false;
}

static void
interruptServer(UA_InterruptManager *im, uintptr_t interruptHandle,
                void *context, const UA_KeyValueMap *parameters) {
    struct InterruptContext *ic = (struct InterruptContext*)context;
    UA_ServerConfig *config = UA_Server_getConfig(ic->server);

    if(config->shutdownDelay <= 0.0) {
        UA_LOG_INFO(config->logging, UA_LOGCATEGORY_APPLICATION,
                    "Received SIGINT interrupt. Stopping the server.");
        ic->running = false;
        return;
    }

    UA_LOG_INFO(config->logging, UA_LOGCATEGORY_APPLICATION,
                "Received SIGINT interrupt. Stopping the server in %.2fs.",
                config->shutdownDelay / 1000.0);

    UA_UInt32 secondsTillShutdown = (UA_UInt32)(config->shutdownDelay / 1000.0);
    UA_Variant val;
    UA_Variant_setScalar(&val, &secondsTillShutdown, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Server_writeValue(ic->server, UA_NS0ID(SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN), val);
    UA_Server_addTimedCallback(ic->server, shutdownServer, ic, UA_DateTime_nowMonotonic() +
                               (UA_DateTime)(config->shutdownDelay * UA_DATETIME_MSEC), NULL);

    /* Notify the application that the server is stopping */
    if(config->notifyLifecycleState)
        config->notifyLifecycleState(ic->server, UA_LIFECYCLESTATE_STOPPING);
}

UA_StatusCode
UA_Server_runUntilInterrupt(UA_Server *server) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_ServerConfig *config = UA_Server_getConfig(server);
    UA_EventLoop *el = config->eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Get the interrupt manager */
    UA_EventSource *es = el->eventSources;
    while(es) {
        if(es->eventSourceType == UA_EVENTSOURCETYPE_INTERRUPTMANAGER)
            break;
        es = es->next;
    }
    if(!es) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "No Interrupt EventSource configured");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_InterruptManager *im = (UA_InterruptManager*)es;

    /* Register the interrupt */
    struct InterruptContext ic;
    ic.server = server;
    ic.running = true;
    UA_StatusCode retval =
        im->registerInterrupt(im, SIGINT, &UA_KEYVALUEMAP_NULL,
                              interruptServer, &ic);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_APPLICATION,
                     "Could not register the interrupt with status code %s",
                     UA_StatusCode_name(retval));
        return retval;
    }

    /* Run the server */
    retval = UA_Server_run_startup(server);
    if(retval != UA_STATUSCODE_GOOD)
        goto deregister_interrupt;
    while(ic.running) {
        UA_Server_run_iterate(server, true);
    }

    /* Shut down the server */
    retval = UA_Server_run_shutdown(server);

    /* Deregister the interrupt */
 deregister_interrupt:
    im->deregisterInterrupt(im, SIGINT);
    return retval;
}

#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */

/*******************************/
/* Default Connection Settings */
/*******************************/

const UA_ConnectionConfig UA_ConnectionConfig_default = {
    0,       /* .protocolVersion */
    1 << 16, /* .sendBufferSize, 64k per chunk */
    1 << 16, /* .recvBufferSize, 64k per chunk */
    1 << 29, /* .localMaxMessageSize, 512 MB */
    1 << 29, /* .remoteMaxMessageSize, 512 MB */
    1 << 14, /* .localMaxChunkCount, 16k */
    1 << 14  /* .remoteMaxChunkCount, 16k */
};

/***************************/
/* Default Server Settings */
/***************************/

#define MANUFACTURER_NAME "open62541"
#define PRODUCT_NAME "open62541 OPC UA Server"
#define PRODUCT_URI "http://open62541.org"
#define APPLICATION_NAME "open62541-based OPC UA Application"
#define APPLICATION_URI "urn:open62541.unconfigured.application"

/* Upper bound */
#define SECURITY_POLICY_SIZE 14

#define STRINGIFY(arg) #arg
#define VERSION(MAJOR, MINOR, PATCH, LABEL) \
    STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(PATCH) LABEL

static UA_StatusCode
addEndpoint(UA_ServerConfig *conf,
            const UA_SecurityPolicy *securityPolicy,
            UA_MessageSecurityMode securityMode) {
    /* Test if the endpoint already exists */
    for(size_t i = 0; i < conf->endpointsSize; i++) {
        UA_EndpointDescription *ep = &conf->endpoints[i];
        if(!UA_String_equal(&securityPolicy->policyUri, &ep->securityPolicyUri))
            continue;
        if(ep->securityMode != securityMode)
            continue;
        return UA_STATUSCODE_GOOD;
    }

    /* Reallocate the array size */
    UA_EndpointDescription *tmp = (UA_EndpointDescription *)
        UA_realloc(conf->endpoints,
                   sizeof(UA_EndpointDescription) * (1 + conf->endpointsSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    conf->endpoints = tmp;

    /* The following fields are overwritten internally with up-to-date
     * information from the server config:
     *
     * UserTokenPolicies
     * ApplicationDescription (server)
     * ServerCertificate
     * EndpointURL */
    UA_EndpointDescription *endpoint = &conf->endpoints[conf->endpointsSize];
    UA_EndpointDescription_init(endpoint);
    endpoint->transportProfileUri =
        UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
    endpoint->securityMode = securityMode;
    endpoint->securityLevel = securityPolicy->securityLevel;

    UA_StatusCode retval = UA_String_copy(&securityPolicy->policyUri,
                                          &endpoint->securityPolicyUri);

    if(retval == UA_STATUSCODE_GOOD) {
        conf->endpointsSize++;
    } else {
        UA_EndpointDescription_clear(endpoint);
        if(conf->endpointsSize == 0) {
            UA_free(conf->endpoints);
            conf->endpoints = NULL;
        }
    }

    return retval;
}

static UA_StatusCode
setDefaultConfig(UA_ServerConfig *conf, UA_UInt16 portNumber) {
    if(!conf)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* NodeStore */
    if(!conf->nodestore)
        conf->nodestore = UA_Nodestore_ZipTree();

    /* Logging */
    if(conf->logging == NULL)
        conf->logging = UA_Log_Stdout_new(UA_LOGLEVEL_INFO);

    /* EventLoop */
    if(conf->eventLoop == NULL) {
#if defined(UA_ARCHITECTURE_ZEPHYR)
        conf->eventLoop = UA_EventLoop_new_Zephyr(conf->logging);
#elif defined(UA_ARCHITECTURE_LWIP)
        conf->eventLoop = UA_EventLoop_new_LWIP(conf->logging, NULL);
#else
        conf->eventLoop = UA_EventLoop_new_POSIX(conf->logging);
#endif
        if(conf->eventLoop == NULL)
            return UA_STATUSCODE_BADOUTOFMEMORY;

        conf->externalEventLoop = false;

        /* Add the TCP connection manager */
#if defined(UA_ARCHITECTURE_ZEPHYR)
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_Zephyr_TCP(UA_STRING("tcp connection manager"));
#elif defined(UA_ARCHITECTURE_LWIP)
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_LWIP_TCP(UA_STRING("tcp connection manager"));
#else
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_POSIX_TCP(UA_STRING("tcp connection manager"));
#endif
        if(tcpCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)tcpCM);

        /* Add the UDP connection manager */
#if defined(UA_ARCHITECTURE_LWIP)
        UA_ConnectionManager *udpCM =
            UA_ConnectionManager_new_LWIP_UDP(UA_STRING("udp connection manager"));
        if(udpCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)udpCM);
#elif !defined(UA_ARCHITECTURE_ZEPHYR)
        UA_ConnectionManager *udpCM =
            UA_ConnectionManager_new_POSIX_UDP(UA_STRING("udp connection manager"));
        if(udpCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)udpCM);
#endif

        /* Add the Ethernet connection manager */
#if !defined(UA_ARCHITECTURE_ZEPHYR) && !defined(UA_ARCHITECTURE_LWIP) && defined(UA_ARCHITECTURE_POSIX) && (defined(__linux__))
        UA_ConnectionManager *ethCM =
            UA_ConnectionManager_new_POSIX_Ethernet(UA_STRING("eth connection manager"));
        if(ethCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)ethCM);
#endif

#if !defined(UA_ARCHITECTURE_ZEPHYR) && !defined(UA_ARCHITECTURE_LWIP)
        /* Add the interrupt manager */
        UA_InterruptManager *im = UA_InterruptManager_new_POSIX(UA_STRING("interrupt manager"));
        if(im) {
            conf->eventLoop->registerEventSource(conf->eventLoop, &im->eventSource);
        } else {
            UA_LOG_ERROR(conf->logging, UA_LOGCATEGORY_APPLICATION,
                         "Cannot create the Interrupt Manager (only relevant if used)");
        }
#endif
#ifdef UA_ENABLE_MQTT
        /* Add the MQTT connection manager */
        UA_ConnectionManager *mqttCM =
            UA_ConnectionManager_new_MQTT(UA_STRING("mqtt connection manager"));
        if(mqttCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)mqttCM);
#endif
    }
    if(conf->eventLoop != NULL) {
        if(conf->eventLoop->state != UA_EVENTLOOPSTATE_STARTED) {
            UA_StatusCode statusCode = conf->eventLoop->start(conf->eventLoop);
            if(statusCode != UA_STATUSCODE_GOOD) {
                return statusCode;
            }
        }
    }

    /* If a second server is started later it can "steal" the port.
     * Having port reuse enabled is important for development.
     * Otherwise a long TCP TIME_WAIT is required before the port can be used again. */
    conf->tcpReuseAddr = true;

    /* --> Start setting the default static config <-- */

    conf->shutdownDelay = 0.0;

    /* Server Description */
    UA_BuildInfo_clear(&conf->buildInfo);
    conf->buildInfo.productUri = UA_STRING_ALLOC(PRODUCT_URI);
    conf->buildInfo.manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME);
    conf->buildInfo.productName = UA_STRING_ALLOC(PRODUCT_NAME);
    conf->buildInfo.softwareVersion =
        UA_STRING_ALLOC(VERSION(UA_OPEN62541_VER_MAJOR, UA_OPEN62541_VER_MINOR,
                                UA_OPEN62541_VER_PATCH, UA_OPEN62541_VER_LABEL));
    conf->buildInfo.buildNumber = UA_STRING_ALLOC(__DATE__ " " __TIME__);
    conf->buildInfo.buildDate = UA_DateTime_now();

    UA_ApplicationDescription_clear(&conf->applicationDescription);
    conf->applicationDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI);
    conf->applicationDescription.productUri = UA_STRING_ALLOC(PRODUCT_URI);
    conf->applicationDescription.applicationName =
        UA_LOCALIZEDTEXT_ALLOC("en", APPLICATION_NAME);
    conf->applicationDescription.applicationType = UA_APPLICATIONTYPE_SERVER;
    /* conf->applicationDescription.gatewayServerUri = UA_STRING_NULL; */
    /* conf->applicationDescription.discoveryProfileUri = UA_STRING_NULL; */
    /* conf->applicationDescription.discoveryUrlsSize = 0; */
    /* conf->applicationDescription.discoveryUrls = NULL; */

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_MdnsDiscoveryConfiguration_clear(&conf->mdnsConfig);
# ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD
    conf->mdnsInterfaceIP = UA_STRING_NULL;
#  if !defined(UA_HAS_GETIFADDR)
    conf->mdnsIpAddressList = NULL;
    conf->mdnsIpAddressListSize = 0;
#  endif
# endif
#endif

    /* Custom DataTypes */
    /* conf->customDataTypesSize = 0; */
    /* conf->customDataTypes = NULL; */

    /* Networking */
    /* Set up the local ServerUrls. They are used during startup to initialize
     * the server sockets. */
    UA_String serverUrls[1];
    size_t serverUrlsSize = 0;
    char serverUrlBuffer[1][512];

    if(portNumber == 0) {
        UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_APPLICATION,
                       "Dynamic port assignment will be used.");
    }

    if(conf->serverUrlsSize > 0) {
        UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_APPLICATION,
                       "ServerUrls already set. Overriding.");
        UA_Array_delete(conf->serverUrls, conf->serverUrlsSize,
                        &UA_TYPES[UA_TYPES_STRING]);
        conf->serverUrls = NULL;
        conf->serverUrlsSize = 0;
    }

    /* Listen on all interfaces (also external). This must be the first
     * entry if this is desired. Otherwise some interfaces may be blocked
     * (already in use) with a hostname that is only locally reachable.*/
    mp_snprintf(serverUrlBuffer[0], sizeof(serverUrlBuffer[0]),
                "opc.tcp://:%u", portNumber);
    serverUrls[serverUrlsSize] = UA_STRING(serverUrlBuffer[0]);
    serverUrlsSize++;

    /* Add to the config */
    UA_StatusCode retval =
        UA_Array_copy(serverUrls, serverUrlsSize,
                      (void**)&conf->serverUrls, &UA_TYPES[UA_TYPES_STRING]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    conf->serverUrlsSize = serverUrlsSize;

    /* Endpoints */
    /* conf->endpoints = {0, NULL}; */

    /* Set Logger for Certificate Verification */
    if(!conf->secureChannelPKI.logging)
        conf->secureChannelPKI.logging = conf->logging;
    if(!conf->sessionPKI.logging)
        conf->sessionPKI.logging = conf->logging;

#ifdef UA_ENABLE_ENCRYPTION
    /* Limits for TrustList */
    conf->maxTrustListSize = 0;
    conf->maxRejectedListSize = 0;
#endif

    /* Certificate Verification that accepts every certificate. Can be
     * overwritten when the policy is specialized. */
    UA_CertificateGroup_AcceptAll(&conf->secureChannelPKI);
    UA_CertificateGroup_AcceptAll(&conf->sessionPKI);

    /* * Global Node Lifecycle * */
    /* conf->nodeLifecycle.constructor = NULL; */
    /* conf->nodeLifecycle.destructor = NULL; */
    /* conf->nodeLifecycle.createOptionalChild = NULL; */
    /* conf->nodeLifecycle.generateChildNodeId = NULL; */
    conf->modellingRulesOnInstances = true;

    /* Limits for SecureChannels */
    conf->maxSecureChannels = 100;
    conf->maxSecurityTokenLifetime = 10 * 60 * 1000; /* 10 minutes */

    /* Limits for Sessions */
    conf->maxSessions = 100;
    conf->maxSessionTimeout = 60.0 * 60.0 * 1000.0; /* 1h */

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Limits for Subscriptions */
    conf->publishingIntervalLimits = UA_DURATIONRANGE(100.0, 3600.0 * 1000.0);
    conf->lifeTimeCountLimits = UA_UINT32RANGE(3, 15000);
    conf->keepAliveCountLimits = UA_UINT32RANGE(1, 100);
    conf->maxNotificationsPerPublish = 1000;
    conf->enableRetransmissionQueue = true;
    conf->maxRetransmissionQueueSize = 0; /* unlimited */
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    conf->maxEventsPerNode = 0; /* unlimited */
# endif

    /* Limits for MonitoredItems */
    conf->samplingIntervalLimits = UA_DURATIONRANGE(50.0, 24.0 * 3600.0 * 1000.0);
    conf->queueSizeLimits = UA_UINT32RANGE(1, 100);
#endif

#ifdef UA_ENABLE_DISCOVERY
    conf->discoveryCleanupTimeout = 60 * 60;
#endif

#ifdef UA_ENABLE_HISTORIZING
    /* conf->accessHistoryDataCapability = false; */
    /* conf->maxReturnDataValues = 0; */

    /* conf->accessHistoryEventsCapability = false; */
    /* conf->maxReturnEventValues = 0; */

    /* conf->insertDataCapability = false; */
    /* conf->insertEventCapability = false; */
    /* conf->insertAnnotationsCapability = false; */

    /* conf->replaceDataCapability = false; */
    /* conf->replaceEventCapability = false; */

    /* conf->updateDataCapability = false; */
    /* conf->updateEventCapability = false; */

    /* conf->deleteRawCapability = false; */
    /* conf->deleteEventCapability = false; */
    /* conf->deleteAtTimeDataCapability = false; */
#endif

#if UA_MULTITHREADING >= 100
    conf->maxAsyncOperationQueueSize = 0;
    conf->asyncOperationTimeout = 120000; /* Async Operation Timeout in ms (2 minutes) */
#endif

#ifdef UA_ENABLE_PUBSUB
    conf->pubsubEnabled = true;
    conf->pubSubConfig.enableDeltaFrames = true;
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    conf->pubSubConfig.enableInformationModelMethods = true;
#endif
#endif

    /* --> Finish setting the default static config <-- */

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setBasics(UA_ServerConfig* conf) {
    return UA_ServerConfig_setBasics_withPort(conf, 4840);
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setBasics_withPort(UA_ServerConfig* conf, UA_UInt16 portNumber) {
    return setDefaultConfig(conf, portNumber);
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyNone(UA_ServerConfig *config,
                                      const UA_ByteString *certificate) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    UA_StatusCode retval =
        UA_SecurityPolicy_None(&config->securityPolicies[config->securityPoliciesSize],
                               localCertificate, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addEndpoint(UA_ServerConfig *config, const UA_String securityPolicyUri,
                            UA_MessageSecurityMode securityMode) {
    /* Lookup the security policy */
    const UA_SecurityPolicy *policy = NULL;
    for (size_t i = 0; i < config->securityPoliciesSize; ++i) {
        if (UA_String_equal(&securityPolicyUri, &config->securityPolicies[i].policyUri)) {
            policy = &config->securityPolicies[i];
            break;
        }
    }
    if(!policy)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Populate the endpoint */
    return addEndpoint(config, policy, securityMode);
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addAllEndpoints(UA_ServerConfig *config) {
    /* Populate the endpoints */
    for(size_t i = 0; i < config->securityPoliciesSize; ++i) {
        if(UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &config->securityPolicies[i].policyUri)) {
            UA_StatusCode retval =
                addEndpoint(config, &config->securityPolicies[i], UA_MESSAGESECURITYMODE_NONE);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        } else {
            UA_StatusCode retval =
                addEndpoint(config, &config->securityPolicies[i], UA_MESSAGESECURITYMODE_SIGN);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
            retval = addEndpoint(config, &config->securityPolicies[i],
                                 UA_MESSAGESECURITYMODE_SIGNANDENCRYPT);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        }
    }

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addAllSecureEndpoints(UA_ServerConfig *config) {

    /* Delete all predefined endpoints. */
    if(config->endpointsSize > 0) {
        for(size_t i = 0; i < config->endpointsSize; ++i)
            UA_EndpointDescription_clear(&config->endpoints[i]);

        UA_free(config->endpoints);
        config->endpoints = NULL;
        config->endpointsSize = 0;
    }

    /* Populate the endpoints */
    for(size_t i = 0; i < config->securityPoliciesSize; ++i) {
        /* Skip the None and all deprecated policies */
        if(config->securityPolicies[i].securityLevel == 0)
            continue;
        UA_StatusCode retval =
            addEndpoint(config, &config->securityPolicies[i], UA_MESSAGESECURITYMODE_SIGN);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        retval = addEndpoint(config, &config->securityPolicies[i],
                             UA_MESSAGESECURITYMODE_SIGNANDENCRYPT);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setMinimalCustomBuffer(UA_ServerConfig *config, UA_UInt16 portNumber,
                                       const UA_ByteString *certificate,
                                       UA_UInt32 sendBufferSize,
                                       UA_UInt32 recvBufferSize) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode retval = setDefaultConfig(config, portNumber);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(config);
        return retval;
    }

    /* Set the TCP settings */
    config->tcpBufSize = recvBufferSize;

    /* Allocate the SecurityPolicies */
    retval = UA_ServerConfig_addSecurityPolicyNone(config, certificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(config);
        return retval;
    }

    /* Initialize the Access Control plugin */
    retval = UA_AccessControl_default(config, true, NULL, 0, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(config);
        return retval;
    }

    /* Allocate the endpoint */
    retval = UA_ServerConfig_addEndpoint(config, UA_SECURITY_POLICY_NONE_URI,
                                         UA_MESSAGESECURITYMODE_NONE);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(config);
        return retval;
    }

    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_ENCRYPTION

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyBasic128Rsa15(UA_ServerConfig *config,
                                               const UA_ByteString *certificate,
                                               const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize],
                                        localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyBasic256(UA_ServerConfig *config,
                                          const UA_ByteString *certificate,
                                          const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize],
                                   localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyBasic256Sha256(UA_ServerConfig *config,
                                                const UA_ByteString *certificate,
                                                const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize],
                                         localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(UA_ServerConfig *config,
                                                const UA_ByteString *certificate,
                                                const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Aes128Sha256RsaOaep(&config->securityPolicies[config->securityPoliciesSize],
                                              localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(UA_ServerConfig *config,
                                                     const UA_ByteString *certificate,
                                                     const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Aes256Sha256RsaPss(&config->securityPolicies[config->securityPoliciesSize],
                                              localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || \
    (defined(UA_ENABLE_ENCRYPTION_MBEDTLS) && MBEDTLS_VERSION_NUMBER >= 0x03000000)
UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccNistP256(UA_ServerConfig *config,
                                                     const UA_ByteString *certificate,
                                                     const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccNistP256(&config->securityPolicies[config->securityPoliciesSize],
                                              UA_APPLICATIONTYPE_SERVER, localCertificate,
                                              localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

/* The AEAD ECC policies (AesGcm / ChaChaPoly) are only implemented in the
 * OpenSSL backend; their constructors do not exist for mbedTLS. */
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccNistP256AesGcm(UA_ServerConfig *config,
                                                    const UA_ByteString *certificate,
                                                    const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccNistP256AesGcm(&config->securityPolicies[config->securityPoliciesSize],
                                              UA_APPLICATIONTYPE_SERVER, localCertificate,
                                              localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccNistP256ChaChaPoly(UA_ServerConfig *config,
                                                       const UA_ByteString *certificate,
                                                       const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccNistP256ChaChaPoly(&config->securityPolicies[config->securityPoliciesSize],
                                                UA_APPLICATIONTYPE_SERVER, localCertificate,
                                                localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}
#endif /* UA_ENABLE_ENCRYPTION_OPENSSL (AEAD ECC policies) */

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccNistP384(UA_ServerConfig *config,
                                             const UA_ByteString *certificate,
                                             const UA_ByteString *privateKey) {
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccNistP384(&config->securityPolicies[config->securityPoliciesSize],
                                      UA_APPLICATIONTYPE_SERVER, localCertificate,
                                      localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}
UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccBrainpoolP256r1(UA_ServerConfig *config,
                                                    const UA_ByteString *certificate,
                                                    const UA_ByteString *privateKey) {
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccBrainpoolP256r1(&config->securityPolicies[config->securityPoliciesSize],
                                             UA_APPLICATIONTYPE_SERVER, localCertificate,
                                             localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}
UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccBrainpoolP384r1(UA_ServerConfig *config,
                                                    const UA_ByteString *certificate,
                                                    const UA_ByteString *privateKey) {
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccBrainpoolP384r1(&config->securityPolicies[config->securityPoliciesSize],
                                             UA_APPLICATIONTYPE_SERVER, localCertificate,
                                             localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}
#endif /* UA_ENABLE_ENCRYPTION_OPENSSL || mbedTLS ECC */

#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccCurve25519(UA_ServerConfig *config,
                                               const UA_ByteString *certificate,
                                               const UA_ByteString *privateKey) {
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccCurve25519(&config->securityPolicies[config->securityPoliciesSize],
                                        UA_APPLICATIONTYPE_SERVER, localCertificate,
                                        localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}
UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyEccCurve448(UA_ServerConfig *config,
                                             const UA_ByteString *certificate,
                                             const UA_ByteString *privateKey) {
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_EccCurve448(&config->securityPolicies[config->securityPoliciesSize],
                                      UA_APPLICATIONTYPE_SERVER, localCertificate,
                                      localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}
#endif


/* This assumes that the sp array has enough space for up to SECURITY_POLICY_SIZE policies.
 * Policies that have been added are not cleaned up after an error.
 * Certificate and/or pricateKey can be NULL and will not be used then.
 * Logs a warning if policies could not be added. */
static void
addAllSecurityPolicies(UA_SecurityPolicy *sp, size_t *length,
                       const UA_ByteString certificate, const UA_ByteString privateKey,
                       UA_Boolean onlySecure, UA_ApplicationType applicationType,
                       UA_Logger *logging) {
    /* Basic256Sha256 */
    UA_StatusCode retval = UA_SecurityPolicy_Basic256Sha256(sp + *length, certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* Aes256Sha256RsaPss */
    retval = UA_SecurityPolicy_Aes256Sha256RsaPss(sp + *length, certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* Aes128Sha256RsaOaep */
    retval = UA_SecurityPolicy_Aes128Sha256RsaOaep(sp + *length, certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* The non-deprecated ECC SecurityPolicies are the AEAD profiles, which are
     * implemented only in the OpenSSL backend. The deprecated non-AEAD ECC
     * policies (EccNistP256/P384, EccBrainpoolP256r1/P384r1) are not part of the
     * default set; add them explicitly via UA_ServerConfig_addSecurityPolicyEcc*. */
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
    /* EccNistP256AesGcm */
    retval = UA_SecurityPolicy_EccNistP256AesGcm(sp + *length, applicationType,
                                                  certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#EccNistP256_AesGcm with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* EccNistP256ChaChaPoly */
    retval = UA_SecurityPolicy_EccNistP256ChaChaPoly(sp + *length, applicationType,
                                                     certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#EccNistP256_ChaChaPoly with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* EccCurve25519 */
    retval = UA_SecurityPolicy_EccCurve25519(sp + *length, applicationType,
                                             certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#EccCurve25519 with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* EccCurve448 */
    retval = UA_SecurityPolicy_EccCurve448(sp + *length, applicationType,
                                           certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#EccCurve448 with error code %s",
                       UA_StatusCode_name(retval));
    }
#endif

    /* Don't add "unsecure" SecurityPolicies */
    if(onlySecure)
        return;

    /* None */
    retval = UA_SecurityPolicy_None(sp + *length, certificate, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#None with error code %s",
                       UA_StatusCode_name(retval));
    }

#ifdef UA_INCLUDE_INSECURE_POLICIES
    /* Basic128Rsa15 should no longer be used */
    retval = UA_SecurityPolicy_Basic128Rsa15(sp + *length, certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* Basic256 should no longer be used */
    retval = UA_SecurityPolicy_Basic256(sp + *length, certificate, privateKey, logging);
    *length += (retval == UA_STATUSCODE_GOOD) ? 1 : 0;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Basic256 with error code %s",
                       UA_StatusCode_name(retval));
    }
#endif

    /* The non-AEAD ECC SecurityPolicies (EccNistP256/P384,
     * EccBrainpoolP256r1/P384r1) are deprecated (OPC UA Part 7), superseded by
     * their *_AesGcm / *_ChaChaPoly variants. They are not part of the default
     * policy set; use the UA_ServerConfig_addSecurityPolicyEcc* functions to add
     * them explicitly. */
}

static UA_StatusCode
addAllServerSecurityPolicies(UA_ServerConfig *config,
                             const UA_ByteString *certificate, const UA_ByteString *privateKey,
                             UA_Boolean onlySecure) {
    /* Populate the cert variables */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;

    /* Load the private key and convert to the DER format. Use an empty password
     * on the first try -- maybe the key does not require a password. */
    UA_ByteString decryptedPrivateKey = UA_BYTESTRING_NULL;
    UA_ByteString keyPassword = UA_BYTESTRING_NULL;
    UA_StatusCode keySuccess = UA_STATUSCODE_GOOD;
    if(privateKey && privateKey->length > 0)
        keySuccess = UA_CertificateUtils_decryptPrivateKey(localPrivateKey, keyPassword,
                                                           &decryptedPrivateKey);

    /* Get the password and decrypt. An application might want to loop / retry
     * here to allow users to correct their entry. */
    if(keySuccess != UA_STATUSCODE_GOOD) {
        if(config->privateKeyPasswordCallback)
            keySuccess = config->privateKeyPasswordCallback(config, &keyPassword);
        else
            keySuccess = readPrivateKeyPassword(&keyPassword);
        if(keySuccess != UA_STATUSCODE_GOOD)
            return keySuccess;
        keySuccess = UA_CertificateUtils_decryptPrivateKey(localPrivateKey, keyPassword,
                                                           &decryptedPrivateKey);
        UA_ByteString_memZero(&keyPassword);
        UA_ByteString_clear(&keyPassword);
    }
    if(keySuccess != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_APPLICATION,
                     "Could not decrypt the private key with status code %s",
                     UA_StatusCode_name(keySuccess));
        return keySuccess;
    }

    /* Clear up the old SecurityPolicies */
    for(size_t i = 0; i < config->securityPoliciesSize; i++) {
        config->securityPolicies[i].clear(&config->securityPolicies[i]);
    }

    /* Allocate memory for the additional policies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy*)
        UA_realloc(config->securityPolicies, sizeof(UA_SecurityPolicy) * SECURITY_POLICY_SIZE);
    if(!tmp) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    config->securityPolicies = tmp;
    config->securityPoliciesSize = 0;

    /* Do the generic addition of certificates */
    addAllSecurityPolicies(config->securityPolicies, &config->securityPoliciesSize,
                           localCertificate, decryptedPrivateKey, onlySecure,
                           UA_APPLICATIONTYPE_SERVER, config->logging);

    if(config->securityPoliciesSize == 0) {
        UA_free(config->securityPolicies);
        config->securityPolicies = NULL;
    }

    UA_ByteString_memZero(&decryptedPrivateKey);
    UA_ByteString_clear(&decryptedPrivateKey);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ServerConfig_addAllSecurityPolicies(UA_ServerConfig *config,
                                       const UA_ByteString *certificate,
                                       const UA_ByteString *privateKey) {
    return addAllServerSecurityPolicies(config, certificate, privateKey, false);
}

/* Always returns UA_STATUSCODE_GOOD. Logs a warning if policies could not be added. */
UA_StatusCode
UA_ServerConfig_addAllSecureSecurityPolicies(UA_ServerConfig *config,
                                             const UA_ByteString *certificate,
                                             const UA_ByteString *privateKey) {
    return addAllServerSecurityPolicies(config, certificate, privateKey, true);
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setDefaultWithSecurityPolicies(UA_ServerConfig *conf,
                                               UA_UInt16 portNumber,
                                               const UA_ByteString *certificate,
                                               const UA_ByteString *privateKey,
                                               const UA_ByteString *trustList,
                                               size_t trustListSize,
                                               const UA_ByteString *issuerList,
                                               size_t issuerListSize,
                                               const UA_ByteString *revocationList,
                                               size_t revocationListSize) {
    UA_StatusCode retval = setDefaultConfig(conf, portNumber);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(conf);
        return retval;
    }

    if(trustListSize > 0) {
        UA_TrustListDataType list;
        UA_TrustListDataType_init(&list);
        list.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES;
        retval = UA_Array_copy(trustList, trustListSize,
                               (void**)&list.trustedCertificates,
                               &UA_TYPES[UA_TYPES_BYTESTRING]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        list.trustedCertificatesSize = trustListSize;

        if(issuerListSize > 0) {
            list.specifiedLists |= UA_TRUSTLISTMASKS_ISSUERCERTIFICATES;
            retval = UA_Array_copy(issuerList, issuerListSize,
                                   (void**)&list.issuerCertificates,
                                   &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_TrustListDataType_clear(&list);
                return retval;
            }
            list.issuerCertificatesSize = issuerListSize;
        }

        if(revocationListSize > 0) {
            list.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCRLS;
            retval = UA_Array_copy(revocationList, revocationListSize,
                                   (void**)&list.trustedCrls,
                                   &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_TrustListDataType_clear(&list);
                return retval;
            }
            list.trustedCrlsSize = revocationListSize;
        }

        /* Set up the parameters */
        UA_KeyValuePair params[2];
        size_t paramsSize = 2;

        params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
        UA_Variant_setScalar(&params[0].value, &conf->maxTrustListSize,
                             &UA_TYPES[UA_TYPES_UINT32]);
        params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
        UA_Variant_setScalar(&params[1].value, &conf->maxRejectedListSize,
                             &UA_TYPES[UA_TYPES_UINT32]);

        UA_KeyValueMap paramsMap;
        paramsMap.map = params;
        paramsMap.mapSize = paramsSize;

        UA_NodeId defaultApplicationGroup =
            UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
        retval = UA_CertificateGroup_Memorystore(&conf->secureChannelPKI,
                                                 &defaultApplicationGroup, &list,
                                                 conf->logging, &paramsMap);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_TrustListDataType_clear(&list);
            return retval;
        }

        UA_NodeId defaultUserTokenGroup =
            UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
        retval = UA_CertificateGroup_Memorystore(&conf->sessionPKI,
                                                 &defaultUserTokenGroup, &list,
                                                 conf->logging, &paramsMap);
        UA_TrustListDataType_clear(&list);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    } else {
        UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_APPLICATION,
                       "Empty trustlist passed. Leaving the previously "
                       "configured certificate verification in place");
    }

    retval = UA_ServerConfig_addAllSecurityPolicies(conf, certificate, privateKey);

    /* Reinitialize AccessControl to take the changed SecurityPolicies into account
     * TODO: This looses username/pw during the reinitialization */
    if(retval == UA_STATUSCODE_GOOD)
        retval = UA_AccessControl_default(conf, true, NULL, 0, NULL);

    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(conf);
        return retval;
    }

    retval = UA_ServerConfig_addAllEndpoints(conf);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(conf);
        return retval;
    }

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setDefaultWithSecureSecurityPolicies(UA_ServerConfig *conf,
                                               UA_UInt16 portNumber,
                                               const UA_ByteString *certificate,
                                               const UA_ByteString *privateKey,
                                               const UA_ByteString *trustList,
                                               size_t trustListSize,
                                               const UA_ByteString *issuerList,
                                               size_t issuerListSize,
                                               const UA_ByteString *revocationList,
                                               size_t revocationListSize) {
    UA_StatusCode retval = setDefaultConfig(conf, portNumber);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(conf);
        return retval;
    }

    if(trustListSize > 0) {
        UA_TrustListDataType list;
        UA_TrustListDataType_init(&list);
        list.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES;
        retval = UA_Array_copy(trustList, trustListSize,
                               (void**)&list.trustedCertificates,
                               &UA_TYPES[UA_TYPES_BYTESTRING]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        list.trustedCertificatesSize = trustListSize;

        if(issuerListSize > 0) {
            list.specifiedLists |= UA_TRUSTLISTMASKS_ISSUERCERTIFICATES;
            retval = UA_Array_copy(issuerList, issuerListSize,
                                   (void**)&list.issuerCertificates,
                                   &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_TrustListDataType_clear(&list);
                return retval;
            }
            list.issuerCertificatesSize = issuerListSize;
        }

        if(revocationListSize > 0) {
            list.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCRLS;
            retval = UA_Array_copy(revocationList, revocationListSize,
                                   (void**)&list.trustedCrls,
                                   &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_TrustListDataType_clear(&list);
                return retval;
            }
            list.trustedCrlsSize = revocationListSize;
        }

        /* Set up the parameters */
        UA_KeyValuePair params[2];
        size_t paramsSize = 2;

        params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
        UA_Variant_setScalar(&params[0].value, &conf->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
        params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
        UA_Variant_setScalar(&params[1].value, &conf->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);

        UA_KeyValueMap paramsMap;
        paramsMap.map = params;
        paramsMap.mapSize = paramsSize;

        UA_NodeId defaultApplicationGroup =
            UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
        retval = UA_CertificateGroup_Memorystore(&conf->secureChannelPKI, &defaultApplicationGroup,
                                                 &list, conf->logging, &paramsMap);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_TrustListDataType_clear(&list);
            return retval;
        }

        UA_NodeId defaultUserTokenGroup =
            UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
        retval = UA_CertificateGroup_Memorystore(&conf->sessionPKI, &defaultUserTokenGroup,
                                                 &list, conf->logging, &paramsMap);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_TrustListDataType_clear(&list);
            return retval;
        }
        UA_TrustListDataType_clear(&list);
    } else {
        UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_APPLICATION,
                       "Empty trustlist passed. Leaving the previously "
                       "configured certificate verification in place");
    }

    retval = UA_ServerConfig_addAllSecureSecurityPolicies(conf, certificate, privateKey);

    if(retval == UA_STATUSCODE_GOOD) {
        retval = UA_AccessControl_default(conf, false, NULL, 0, NULL);
    }
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(conf);
        return retval;
    }

    retval = UA_ServerConfig_addAllSecureEndpoints(conf);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(conf);
        return retval;
    }

    return UA_STATUSCODE_GOOD;
}

#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)

UA_StatusCode
UA_ServerConfig_addSecurityPolicy_Filestore(UA_ServerConfig *config,
                                            UA_SecurityPolicy *innerPolicy,
                                            const UA_String storePath) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    UA_StatusCode retval =
        UA_SecurityPolicy_Filestore(&config->securityPolicies[config->securityPoliciesSize],
                                    innerPolicy, storePath);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ServerConfig_addSecurityPolicies_Filestore(UA_ServerConfig *config,
                                              const UA_ByteString *certificate,
                                              const UA_ByteString *privateKey,
                                              const UA_String storePath) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_Boolean onlySecure = false;
    UA_Boolean onlyNone = false;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;

    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;

    if(certificate && privateKey) {
        size_t certificateKeyLength = 0;
        if(UA_CertificateUtils_getKeySize((UA_ByteString*)(uintptr_t)certificate,
                                          &certificateKeyLength) == UA_STATUSCODE_GOOD &&
           certificateKeyLength > 2048)
            onlySecure = true;
    } else {
        onlyNone = true;
    }

    /* Load the private key and convert to the DER format. Use an empty password
     * on the first try -- maybe the key does not require a password. */
    UA_ByteString decryptedPrivateKey = UA_BYTESTRING_NULL;
    UA_ByteString keyPassword = UA_BYTESTRING_NULL;
    UA_StatusCode keySuccess = UA_STATUSCODE_GOOD;

    if(privateKey && privateKey->length > 0)
        keySuccess = UA_CertificateUtils_decryptPrivateKey(localPrivateKey, keyPassword,
                                              &decryptedPrivateKey);

    /* Get the password and decrypt. An application might want to loop / retry
     * here to allow users to correct their entry. */
    if(keySuccess != UA_STATUSCODE_GOOD) {
        if(config->privateKeyPasswordCallback)
            keySuccess = config->privateKeyPasswordCallback(config, &keyPassword);
        else
            keySuccess = readPrivateKeyPassword(&keyPassword);
        if(keySuccess != UA_STATUSCODE_GOOD)
            return keySuccess;
        keySuccess = UA_CertificateUtils_decryptPrivateKey(localPrivateKey, keyPassword,
                                              &decryptedPrivateKey);
        UA_ByteString_memZero(&keyPassword);
        UA_ByteString_clear(&keyPassword);
    }
    if(keySuccess != UA_STATUSCODE_GOOD)
        return keySuccess;

    if(onlyNone) {
        /* None */
        UA_SecurityPolicy *nonePolicy =
            (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
        if(!nonePolicy) {
            UA_ByteString_memZero(&decryptedPrivateKey);
            UA_ByteString_clear(&decryptedPrivateKey);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        retval = UA_SecurityPolicy_None(nonePolicy, localCertificate, config->logging);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#None with error code %s",
                           UA_StatusCode_name(retval));
            nonePolicy->clear(nonePolicy);
            UA_free(nonePolicy);
            nonePolicy = NULL;
        } else {
            retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, nonePolicy, storePath);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                               "Could not add SecurityPolicy#None with error code %s",
                               UA_StatusCode_name(retval));
            }
        }
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return retval;
    }

    /* Basic256Sha256 */
    UA_SecurityPolicy *basic256Sha256Policy =
        (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
    if(!basic256Sha256Policy) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    retval = UA_SecurityPolicy_Basic256Sha256(basic256Sha256Policy, localCertificate,
                                              decryptedPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                       UA_StatusCode_name(retval));
        basic256Sha256Policy->clear(basic256Sha256Policy);
        UA_free(basic256Sha256Policy);
        basic256Sha256Policy = NULL;
    } else {
        retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, basic256Sha256Policy, storePath);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                           UA_StatusCode_name(retval));
        }
    }

    /* Aes256Sha256RsaPss */
    UA_SecurityPolicy *aes256Sha256RsaPssPolicy =
        (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
    if(!aes256Sha256RsaPssPolicy) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    retval = UA_SecurityPolicy_Aes256Sha256RsaPss(aes256Sha256RsaPssPolicy, localCertificate,
                                                  decryptedPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
                       UA_StatusCode_name(retval));
        aes256Sha256RsaPssPolicy->clear(aes256Sha256RsaPssPolicy);
        UA_free(aes256Sha256RsaPssPolicy);
        aes256Sha256RsaPssPolicy = NULL;
    } else {
        retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, aes256Sha256RsaPssPolicy, storePath);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
                           UA_StatusCode_name(retval));
        }
    }

    /* Aes128Sha256RsaOaep */
    UA_SecurityPolicy *aes128Sha256RsaOaepPolicy =
        (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
    if(!aes128Sha256RsaOaepPolicy) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    retval = UA_SecurityPolicy_Aes128Sha256RsaOaep(aes128Sha256RsaOaepPolicy, localCertificate,
                                                   decryptedPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                       UA_StatusCode_name(retval));
        aes128Sha256RsaOaepPolicy->clear(aes128Sha256RsaOaepPolicy);
        UA_free(aes128Sha256RsaOaepPolicy);
        aes128Sha256RsaOaepPolicy = NULL;
    } else {
        retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, aes128Sha256RsaOaepPolicy, storePath);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                           UA_StatusCode_name(retval));
        }
    }

    if(onlySecure) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_GOOD;
    }

    /* None */
    UA_SecurityPolicy *nonePolicy =
        (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
    if(!nonePolicy) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    retval = UA_SecurityPolicy_None(nonePolicy, localCertificate, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#None with error code %s",
                       UA_StatusCode_name(retval));
        nonePolicy->clear(nonePolicy);
        UA_free(nonePolicy);
        nonePolicy = NULL;
    } else {
        retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, nonePolicy, storePath);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#None with error code %s",
                           UA_StatusCode_name(retval));
        }
    }

    /* Basic128Rsa15 */
    UA_SecurityPolicy *basic128Rsa15Policy =
        (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
    if(!basic128Rsa15Policy) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    retval = UA_SecurityPolicy_Basic128Rsa15(basic128Rsa15Policy, localCertificate,
                                             decryptedPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                       UA_StatusCode_name(retval));
        basic128Rsa15Policy->clear(basic128Rsa15Policy);
        UA_free(basic128Rsa15Policy);
        basic128Rsa15Policy = NULL;
    } else {
        retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, basic128Rsa15Policy, storePath);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                           UA_StatusCode_name(retval));
        }
    }

    /* Basic256 */
    UA_SecurityPolicy *basic256Policy =
        (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
    if(!basic256Policy) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    retval = UA_SecurityPolicy_Basic256(basic256Policy, localCertificate,
                                        decryptedPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#Basic256 with error code %s",
                       UA_StatusCode_name(retval));
        basic256Policy->clear(basic256Policy);
        UA_free(basic256Policy);
        basic256Policy = NULL;
    } else {
        retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, basic256Policy, storePath);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#Basic256 with error code %s",
                           UA_StatusCode_name(retval));
        }
    }

    /* EccNistP256AesGcm (OpenSSL-only AEAD policy) */
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
    UA_SecurityPolicy *eccnistp256AesGcmPolicy =
        (UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
    if(!eccnistp256AesGcmPolicy) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    retval = UA_SecurityPolicy_EccNistP256AesGcm(eccnistp256AesGcmPolicy,
                                                  UA_APPLICATIONTYPE_SERVER,
                                                  localCertificate, decryptedPrivateKey,
                                                  config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "Could not add SecurityPolicy#ECC_nistP256_AesGcm with error code %s",
                       UA_StatusCode_name(retval));
        eccnistp256AesGcmPolicy->clear(eccnistp256AesGcmPolicy);
        UA_free(eccnistp256AesGcmPolicy);
        eccnistp256AesGcmPolicy = NULL;
    } else {
        retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, eccnistp256AesGcmPolicy, storePath);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_APPLICATION,
                           "Could not add SecurityPolicy#ECC_nistP256_AesGcm with error code %s",
                           UA_StatusCode_name(retval));
        }
    }
#endif

    /* The non-AEAD ECC SecurityPolicies (EccNistP256/P384,
     * EccBrainpoolP256r1/P384r1) are deprecated (OPC UA Part 7), superseded by
     * their *_AesGcm / *_ChaChaPoly variants. They are not part of the default
     * policy set; use the UA_ServerConfig_addSecurityPolicyEcc* functions to add
     * them explicitly. */

    UA_ByteString_memZero(&decryptedPrivateKey);
    UA_ByteString_clear(&decryptedPrivateKey);
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setDefaultWithFilestore(UA_ServerConfig *conf,
                                        UA_UInt16 portNumber,
                                        const UA_ByteString *certificate,
                                        const UA_ByteString *privateKey,
                                        const UA_String storePath) {
    UA_StatusCode retval = setDefaultConfig(conf, portNumber);
    if(retval != UA_STATUSCODE_GOOD) {
        return retval;
    }

    if(!storePath.data) {
        UA_LOG_ERROR(conf->logging, UA_LOGCATEGORY_APPLICATION,
                     "The path to a PKI folder has not been specified");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Set up the parameters */
    UA_KeyValuePair params[2];
    size_t paramsSize = 2;

    params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
    UA_Variant_setScalar(&params[0].value, &conf->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
    params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
    UA_Variant_setScalar(&params[1].value, &conf->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);

    UA_KeyValueMap paramsMap;
    paramsMap.map = params;
    paramsMap.mapSize = paramsSize;

    UA_NodeId defaultApplicationGroup =
            UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    retval = UA_CertificateGroup_Filestore(&conf->secureChannelPKI, &defaultApplicationGroup,
                                           storePath, conf->logging, &paramsMap);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_NodeId defaultUserTokenGroup =
            UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
    retval = UA_CertificateGroup_Filestore(&conf->sessionPKI, &defaultUserTokenGroup,
                                           storePath, conf->logging, &paramsMap);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_ServerConfig_addSecurityPolicies_Filestore(conf, certificate, privateKey, storePath);

    if(retval == UA_STATUSCODE_GOOD) {
        retval = UA_AccessControl_default(conf, true, NULL, 0, NULL);
    }

    if(retval == UA_STATUSCODE_GOOD) {
        retval = UA_ServerConfig_addAllEndpoints(conf);
    }

    return retval;
}

#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */

#endif /* UA_ENABLE_ENCRYPTION */

#if defined(UA_ENABLE_DISCOVERY) || defined(UA_ENABLE_AMALGAMATION)

/***************************/
/* Default Client Settings */
/***************************/

UA_Client * UA_Client_new(void) {
    UA_ClientConfig config;
    memset(&config, 0, sizeof(UA_ClientConfig));
    /* Set up basic usable config including logger and event loop */
    UA_StatusCode res = UA_ClientConfig_setDefault(&config);
    if(res != UA_STATUSCODE_GOOD)
        return NULL;
    return UA_Client_newWithConfig(&config);
}

#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) || defined(UA_ARCHITECTURE_ZEPHYR)

struct ClientInterruptContext {
    UA_Client *client;
    UA_Boolean running;
};

static void
interruptClient(UA_InterruptManager *im, uintptr_t interruptHandle,
                void *context, const UA_KeyValueMap *parameters) {
    struct ClientInterruptContext *ic = (struct ClientInterruptContext*)context;
    UA_ClientConfig *config = UA_Client_getConfig(ic->client);
    UA_LOG_INFO(config->logging, UA_LOGCATEGORY_APPLICATION, "Stopping the client");
    ic->running = false;
}

UA_StatusCode
UA_Client_runUntilInterrupt(UA_Client *client) {
    if(!client)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_ClientConfig *config = UA_Client_getConfig(client);
    UA_EventLoop *el = config->eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Get the interrupt manager */
    UA_EventSource *es = el->eventSources;
    while(es) {
        if(es->eventSourceType == UA_EVENTSOURCETYPE_INTERRUPTMANAGER)
            break;
        es = es->next;
    }
    if(!es) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_APPLICATION,
                       "No Interrupt EventSource configured");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_InterruptManager *im = (UA_InterruptManager*)es;

    /* Register the interrupt */
    struct ClientInterruptContext ic;
    ic.client = client;
    ic.running = true;
    UA_StatusCode res =
        im->registerInterrupt(im, SIGINT, &UA_KEYVALUEMAP_NULL,
                              interruptClient, &ic);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_APPLICATION,
                     "Could not register the interrupt with status code %s",
                     UA_StatusCode_name(res));
        return res;
    }

    /* Run the client */
    while(ic.running) {
        res = UA_Client_run_iterate(client, 100);
        if(res != UA_STATUSCODE_GOOD)
            break;
    }

    /* Deregister the interrupt */
    im->deregisterInterrupt(im, SIGINT);
    return res;
}

#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */

UA_StatusCode
UA_ClientConfig_setDefault(UA_ClientConfig *config) {
    /* The following fields are untouched and OK to leave as NULL or 0:
     *  clientContext
     *  userIdentityToken
     *  securityMode
     *  securityPolicyUri
     *  endpoint
     *  userTokenPolicy
     *  customDataTypes
     *  connectivityCheckInterval
     *  stateCallback
     *  inactivityCallback
     *  outStandingPublishRequests
     *  subscriptionInactivityCallback
     *  sessionLocaleIds
     *  sessionLocaleIdsSize */

    if(config->timeout == 0)
        config->timeout = 5 * 1000; /* 5 seconds */
    if(config->secureChannelLifeTime == 0)
        config->secureChannelLifeTime = 10 * 60 * 1000; /* 10 minutes */

    if(config->logging == NULL)
        config->logging = UA_Log_Stdout_new(UA_LOGLEVEL_INFO);

    /* EventLoop */
    if(config->eventLoop == NULL) {
#if defined(UA_ARCHITECTURE_ZEPHYR)
        config->eventLoop = UA_EventLoop_new_Zephyr(config->logging);
#elif defined(UA_ARCHITECTURE_LWIP)
        config->eventLoop = UA_EventLoop_new_LWIP(config->logging, NULL);
#else
        config->eventLoop = UA_EventLoop_new_POSIX(config->logging);
#endif
        config->externalEventLoop = false;

        /* Add the TCP connection manager */
#if defined(UA_ARCHITECTURE_ZEPHYR)
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_Zephyr_TCP(UA_STRING("tcp connection manager"));
#elif defined(UA_ARCHITECTURE_LWIP)
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_LWIP_TCP(UA_STRING("tcp connection manager"));
#else
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_POSIX_TCP(UA_STRING("tcp connection manager"));
#endif
        config->eventLoop->registerEventSource(config->eventLoop, (UA_EventSource *)tcpCM);

#if defined(UA_ARCHITECTURE_LWIP)
        UA_ConnectionManager *udpCM =
            UA_ConnectionManager_new_LWIP_UDP(UA_STRING("udp connection manager"));
        if(udpCM)
            config->eventLoop->registerEventSource(config->eventLoop, (UA_EventSource *)udpCM);
#elif !defined(UA_ARCHITECTURE_ZEPHYR)
        /* Add the UDP connection manager */
        UA_ConnectionManager *udpCM =
            UA_ConnectionManager_new_POSIX_UDP(UA_STRING("udp connection manager"));
        config->eventLoop->registerEventSource(config->eventLoop, (UA_EventSource *)udpCM);
#endif

#if !defined(UA_ARCHITECTURE_ZEPHYR) && !defined(UA_ARCHITECTURE_LWIP)
        /* Add the interrupt manager */
        UA_InterruptManager *im = UA_InterruptManager_new_POSIX(UA_STRING("interrupt manager"));
        if(im) {
            config->eventLoop->registerEventSource(config->eventLoop, &im->eventSource);
        } else {
            UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_APPLICATION,
                         "Cannot create the Interrupt Manager (only relevant if used)");
        }
#endif
    }

    if(config->localConnectionConfig.recvBufferSize == 0)
        config->localConnectionConfig = UA_ConnectionConfig_default;

    if(!config->certificateVerification.logging) {
        config->certificateVerification.logging = config->logging;
    }

#ifdef UA_ENABLE_ENCRYPTION
    /* Limits for TrustList */
    config->maxTrustListSize = 0;
    config->maxRejectedListSize = 0;
#endif

    if(!config->certificateVerification.verifyCertificate) {
        /* Certificate Verification that accepts every certificate. Can be
         * overwritten when the policy is specialized. */
        UA_CertificateGroup_AcceptAll(&config->certificateVerification);
    }

    /* With encryption enabled, the applicationUri needs to match the URI from
     * the certificate */
    if(!config->clientDescription.applicationUri.data)
        config->clientDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI);
    if(config->clientDescription.applicationType == 0)
        config->clientDescription.applicationType = UA_APPLICATIONTYPE_CLIENT;

    if(config->securityPoliciesSize == 0) {
        config->securityPolicies = (UA_SecurityPolicy*)UA_malloc(sizeof(UA_SecurityPolicy));
        if(!config->securityPolicies)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        UA_StatusCode retval = UA_SecurityPolicy_None(config->securityPolicies,
                                                      UA_BYTESTRING_NULL, config->logging);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
            return retval;
        }
        config->securityPoliciesSize = 1;
    }

    if(config->requestedSessionTimeout == 0)
        config->requestedSessionTimeout = 1200000;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    if(config->outStandingPublishRequests == 0)
        config->outStandingPublishRequests = 10;
#endif

    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_ENCRYPTION

static UA_StatusCode
clientConfig_setAuthenticationSecurityPolicies(UA_ClientConfig *config,
                                               UA_ByteString certificateAuth,
                                               UA_ByteString privateKeyAuth) {
    for(size_t i = 0; i < config->authSecurityPoliciesSize; i++) {
        config->authSecurityPolicies[i].clear(&config->authSecurityPolicies[i]);
    }

    UA_SecurityPolicy *sp = (UA_SecurityPolicy*)
        UA_realloc(config->authSecurityPolicies, sizeof(UA_SecurityPolicy) * SECURITY_POLICY_SIZE);
    if(!sp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->authSecurityPolicies = sp;
    config->authSecurityPoliciesSize = 0;

    addAllSecurityPolicies(sp, &config->authSecurityPoliciesSize,
                           certificateAuth, privateKeyAuth, false,
                           UA_APPLICATIONTYPE_CLIENT, config->logging);

    if(config->authSecurityPoliciesSize == 0) {
        UA_free(config->authSecurityPolicies);
        config->authSecurityPolicies = NULL;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
clientConfig_setSecurityPolicies(UA_ClientConfig *config,
                                 UA_ByteString certificateAuth,
                                 UA_ByteString privateKeyAuth) {
    for(size_t i = 0; i < config->securityPoliciesSize; i++) {
        config->securityPolicies[i].clear(&config->securityPolicies[i]);
    }

    UA_SecurityPolicy *sp = (UA_SecurityPolicy*)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * SECURITY_POLICY_SIZE);
    if(!sp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = sp;
    config->securityPoliciesSize = 0;

    addAllSecurityPolicies(sp, &config->securityPoliciesSize,
                           certificateAuth, privateKeyAuth, false,
                           UA_APPLICATIONTYPE_CLIENT, config->logging);

    if(config->securityPoliciesSize == 0) {
        UA_free(config->securityPolicies);
        config->securityPolicies = NULL;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ClientConfig_setDefaultEncryption(UA_ClientConfig *config,
                                     UA_ByteString localCertificate, UA_ByteString privateKey,
                                     const UA_ByteString *trustList, size_t trustListSize,
                                     const UA_ByteString *revocationList, size_t revocationListSize) {
    UA_StatusCode retval = UA_ClientConfig_setDefault(config);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(trustListSize > 0) {
        UA_TrustListDataType list;
        UA_TrustListDataType_init(&list);
        list.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES;
        retval = UA_Array_copy(trustList, trustListSize,
                               (void**)&list.trustedCertificates,
                               &UA_TYPES[UA_TYPES_BYTESTRING]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        list.trustedCertificatesSize = trustListSize;

        if(revocationListSize > 0) {
            list.specifiedLists |= UA_TRUSTLISTMASKS_TRUSTEDCRLS;
            retval = UA_Array_copy(revocationList, revocationListSize,
                                   (void**)&list.trustedCrls,
                                   &UA_TYPES[UA_TYPES_BYTESTRING]);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_TrustListDataType_clear(&list);
                return retval;
            }
            list.trustedCrlsSize = revocationListSize;
        }

        /* Set up the parameters */
        UA_KeyValuePair params[2];
        size_t paramsSize = 2;

        params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
        UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize,
                             &UA_TYPES[UA_TYPES_UINT32]);
        params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
        UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize,
                             &UA_TYPES[UA_TYPES_UINT32]);

        UA_KeyValueMap paramsMap;
        paramsMap.map = params;
        paramsMap.mapSize = paramsSize;

        if(config->certificateVerification.clear)
            config->certificateVerification.clear(&config->certificateVerification);
        UA_NodeId defaultApplicationGroup =
            UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
        retval = UA_CertificateGroup_Memorystore(&config->certificateVerification,
                                                 &defaultApplicationGroup, &list,
                                                 config->logging, &paramsMap);
        UA_TrustListDataType_clear(&list);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                       "Empty trustlist passed. Leaving the previously "
                       "configured certificate verification in place");
    }

    /* Load the private key and convert to the DER format. Use an empty password
     * on the first try -- maybe the key does not require a password. */
    UA_ByteString decryptedPrivateKey = UA_BYTESTRING_NULL;
    UA_ByteString keyPassword = UA_BYTESTRING_NULL;
    UA_StatusCode keySuccess = UA_STATUSCODE_GOOD;

    if(privateKey.length > 0)
        keySuccess = UA_CertificateUtils_decryptPrivateKey(privateKey, keyPassword,
                                                           &decryptedPrivateKey);

    /* Get the password and decrypt. An application might want to loop / retry
     * here to allow users to correct their entry. */
    if(keySuccess != UA_STATUSCODE_GOOD) {
        if(config->privateKeyPasswordCallback)
            keySuccess = config->privateKeyPasswordCallback(config, &keyPassword);
        else
            keySuccess = readPrivateKeyPassword(&keyPassword);
        if(keySuccess != UA_STATUSCODE_GOOD)
            return keySuccess;
        keySuccess = UA_CertificateUtils_decryptPrivateKey(privateKey, keyPassword, &decryptedPrivateKey);
        UA_ByteString_memZero(&keyPassword);
        UA_ByteString_clear(&keyPassword);
    }
    if(keySuccess != UA_STATUSCODE_GOOD)
        return keySuccess;

    clientConfig_setSecurityPolicies(config, localCertificate, decryptedPrivateKey);
    clientConfig_setAuthenticationSecurityPolicies(config, localCertificate, decryptedPrivateKey);

    UA_ByteString_memZero(&decryptedPrivateKey);
    UA_ByteString_clear(&decryptedPrivateKey);

    return UA_STATUSCODE_GOOD;
}
#endif

#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
UA_StatusCode
UA_ClientConfig_setAuthenticationCert(UA_ClientConfig *config,
                                      UA_ByteString certificateAuth,
                                      UA_ByteString privateKeyAuth) {
#ifdef UA_ENABLE_ENCRYPTION_LIBRESSL
    UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_APPLICATION,
                 "Certificate authentication with LibreSSL as crypto backend is not supported.");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
#endif

    /* Create UserIdentityToken */
    UA_X509IdentityToken* identityToken = UA_X509IdentityToken_new();
    if(!identityToken)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    /* Don't set identityToken->policyId. This is taken from the appropriate
     * endpoint at runtime. */
    UA_StatusCode retval = UA_ByteString_copy(&certificateAuth, &identityToken->certificateData);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_ExtensionObject_clear(&config->userIdentityToken);
    config->userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED;
    config->userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN];
    config->userIdentityToken.content.decoded.data = identityToken;

    /* Populate SecurityPolicies */
    return clientConfig_setAuthenticationSecurityPolicies(config, certificateAuth, privateKeyAuth);
}
#endif

#endif /* UA_ENABLE_DISCOVERY OR UA_ENABLE_AMALGAMATION*/

/**** amalgamated original file "/plugins/crypto/ua_certificategroup_none.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2020 (c) Julius Pfrommer, Fraunhofer IOSB
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


static UA_StatusCode
verifyCertificateAllowAll(UA_CertificateGroup *certGroup,
                          const UA_ByteString *certificate) {
    UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_APPLICATION,
                   "No certificate store configured. Accepting the certificate.");
    return UA_STATUSCODE_GOOD;
}

static void
clearVerifyAllowAll(UA_CertificateGroup *certGroup) {

}

void UA_CertificateGroup_AcceptAll(UA_CertificateGroup *certGroup) {
    /* Clear the structure, as it may have already been initialized. */
    UA_NodeId groupId = certGroup->certificateGroupId;
    if(certGroup->clear)
        certGroup->clear(certGroup);
    UA_NodeId_copy(&groupId, &certGroup->certificateGroupId);
    certGroup->verifyCertificate = verifyCertificateAllowAll;
    certGroup->clear = clearVerifyAllowAll;
    certGroup->getTrustList = NULL;
    certGroup->setTrustList = NULL;
    certGroup->addToTrustList = NULL;
    certGroup->removeFromTrustList = NULL;
    certGroup->getRejectedList = NULL;
    certGroup->getCertificateCrls = NULL;
}

#ifndef UA_ENABLE_ENCRYPTION
UA_StatusCode
UA_CertificateUtils_verifyApplicationUri(const UA_ByteString *certificate,
                                         const UA_String *applicationURI) {
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
                                      UA_DateTime *expiryDateTime){
    return UA_STATUSCODE_BADNOTSUPPORTED;
}

UA_StatusCode
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
                                   UA_String *subjectName){
    return UA_STATUSCODE_BADNOTSUPPORTED;
}

UA_StatusCode
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
                                  UA_String *thumbprint){
    return UA_STATUSCODE_BADNOTSUPPORTED;
}

UA_StatusCode
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
                                      const UA_ByteString *certificate2) {
    return UA_STATUSCODE_BADNOTSUPPORTED;
}

UA_StatusCode
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
                                 const UA_ByteString *privateKey) {
    return UA_STATUSCODE_BADNOTSUPPORTED;
}

UA_StatusCode
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
    return UA_STATUSCODE_BADNOTSUPPORTED;
}
#endif

/**** amalgamated original file "/plugins/crypto/ua_securitypolicy_none.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS
#endif

#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
#endif

#ifndef UA_ENABLE_ENCRYPTION
/* The URI-derived SecurityPolicy property helpers are normally provided by the
 * crypto backend's securitypolicy_common.c. With no crypto backend the only
 * SecurityPolicy is #None, so they reduce to constants. */
UA_Boolean
UA_SecurityPolicy_isEnhancedSecurity(const UA_SecurityPolicy *policy) {
    (void)policy;
    return false;
}

UA_Boolean
UA_SecurityPolicy_useLegacySequenceNumbers(const UA_SecurityPolicy *policy) {
    (void)policy;
    return true;
}
#endif

static UA_StatusCode
verify_none(const UA_SecurityPolicy *policy, void *channelContext,
            const UA_ByteString *message, const UA_ByteString *signature) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sign_none(const UA_SecurityPolicy *policy, void *channelContext,
          const UA_ByteString *message, UA_ByteString *signature) {
    return UA_STATUSCODE_GOOD;
}

static size_t
length_none(const UA_SecurityPolicy *policy, const void *channelContext) {
    return 0;
}

static UA_StatusCode
encrypt_none(const UA_SecurityPolicy *policy, void *channelContext,
             UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
decrypt_none(const UA_SecurityPolicy *policy, void *channelContext,
             UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
makeThumbprint_none(const UA_SecurityPolicy *policy,
                    const UA_ByteString *certificate,
                    UA_ByteString *thumbprint) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
compareThumbprint_none(const UA_SecurityPolicy *policy,
                       const UA_ByteString *thumbprint) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
generateKey_none(const UA_SecurityPolicy *policy,
                 void *channelContext, const UA_ByteString *secret,
                 const UA_ByteString *seed, UA_ByteString *out) {
    return UA_STATUSCODE_GOOD;
}

/* Use the non-cryptographic RNG to set the nonce */
static UA_StatusCode
generateNonce_none(const UA_SecurityPolicy *policy,
                   void *channelContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(out->length == 0)
        return UA_STATUSCODE_GOOD;

    /* Fill blocks of four byte */
    size_t i = 0;
    while(i + 3 < out->length) {
        UA_UInt32 randNumber = UA_UInt32_random();
        memcpy(&out->data[i], &randNumber, 4);
        i = i+4;
    }

    /* Fill the remaining byte */
    UA_UInt32 randNumber = UA_UInt32_random();
    memcpy(&out->data[i], &randNumber, out->length % 4);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
newContext_none(const UA_SecurityPolicy *securityPolicy,
                const UA_ByteString *remoteCertificate,
                void **channelContext) {
    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_none(const UA_SecurityPolicy *policy, void *channelContext) {
}

static UA_StatusCode
setContextValue_none(const UA_SecurityPolicy *policy,
                     void *channelContext,
                     const UA_ByteString *iv) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
compareCertificate_none(const UA_SecurityPolicy *policy,
                        const void *channelContext,
                        const UA_ByteString *certificate) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
updateCertificate_none(UA_SecurityPolicy *policy,
                       const UA_ByteString certificate,
                       const UA_ByteString privateKey) {
    UA_ByteString_clear(&policy->localCertificate);
    UA_ByteString_copy(&certificate, &policy->localCertificate);
    return UA_STATUSCODE_GOOD;
}


static void
policy_clear_none(UA_SecurityPolicy *policy) {
    UA_ByteString_clear(&policy->localCertificate);
}

UA_StatusCode
UA_SecurityPolicy_None(UA_SecurityPolicy *sp, const UA_ByteString localCertificate,
                       const UA_Logger *logger) {

    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
    sp->certificateGroupId = UA_NODEID_NULL;
    sp->certificateTypeId = UA_NODEID_NULL;
    sp->securityLevel = 0;
    sp->policyType = UA_SECURITYPOLICYTYPE_NONE;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING_NULL;
    symSig->verify = verify_none;
    symSig->sign = sign_none;
    symSig->getLocalSignatureSize = length_none;
    symSig->getRemoteSignatureSize = length_none;
    symSig->getLocalKeyLength = length_none;
    symSig->getRemoteKeyLength = length_none;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING_NULL;
    symEnc->encrypt = encrypt_none;
    symEnc->decrypt = decrypt_none;
    symEnc->getLocalKeyLength = length_none;
    symEnc->getRemoteKeyLength = length_none;
    symEnc->getRemoteBlockSize = length_none;
    symEnc->getRemotePlainTextBlockSize = length_none;

    /* This only works for none since symmetric and asymmetric crypto modules do
     * the same i.e. nothing */
    sp->asymSignatureAlgorithm = sp->symSignatureAlgorithm;
    sp->asymEncryptionAlgorithm = sp->symEncryptionAlgorithm;

    /* Use the same signing algorithm as for asymmetric signing */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = newContext_none;
    sp->deleteChannelContext = deleteContext_none;
    sp->setLocalSymEncryptingKey = setContextValue_none;
    sp->setLocalSymSigningKey = setContextValue_none;
    sp->setLocalSymIv = setContextValue_none;
    sp->setRemoteSymEncryptingKey = setContextValue_none;
    sp->setRemoteSymSigningKey = setContextValue_none;
    sp->setRemoteSymIv = setContextValue_none;
    sp->compareCertificate = compareCertificate_none;
    sp->generateKey = generateKey_none;
    sp->generateNonce = generateNonce_none;
    sp->nonceLength = 0;
    sp->makeCertThumbprint = makeThumbprint_none;
    sp->compareCertThumbprint = compareThumbprint_none;
    sp->updateCertificate = updateCertificate_none;
    sp->createSigningRequest = NULL;
    sp->clear = policy_clear_none;

#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS
    UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
#elif defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
    UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                    EVP_PKEY_NONE);
#else
    UA_ByteString_copy(&localCertificate, &sp->localCertificate);
#endif

    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/arch/posix/clock_posix.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
 */


/* Note that the EventLoop plugin provides its own internal time source (which
 * is typically just the normal system time). All internal access to the time
 * source should be through the EventLoop. The below is therefore for developer
 * convenience to just use UA_DateTime_now(). */

#if defined(UA_ARCHITECTURE_POSIX)

#include <time.h>
#include <sys/time.h>

#if defined(__APPLE__) && defined(__MACH__)
# include <mach/clock.h>
# include <mach/mach.h>
#endif

UA_DateTime UA_DateTime_now(void) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (tv.tv_sec * UA_DATETIME_SEC) +
        (tv.tv_usec * UA_DATETIME_USEC) +
        UA_DATETIME_UNIX_EPOCH;
}

/* Credit to https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c */
UA_Int64 UA_DateTime_localTimeUtcOffset(void) {
    time_t rawtime = time(NULL);
    struct tm gbuf;
    struct tm *ptm = gmtime_r(&rawtime, &gbuf);
    /* Request mktime() to look up dst in timezone database */
    ptm->tm_isdst = -1;
    time_t gmt = mktime(ptm);
    return (UA_Int64) (difftime(rawtime, gmt) * UA_DATETIME_SEC);
}

UA_DateTime UA_DateTime_nowMonotonic(void) {
#if defined(__APPLE__) && defined(__MACH__)
    /* OS X does not have clock_gettime, use clock_get_time */
    clock_serv_t cclock;
    mach_timespec_t mts;
    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
    clock_get_time(cclock, &mts);
    mach_port_deallocate(mach_task_self(), cclock);
    return (mts.tv_sec * UA_DATETIME_SEC) + (mts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#elif !defined(CLOCK_MONOTONIC_RAW)
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#else
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#endif
}

#elif defined(UA_ARCHITECTURE_WIN32)

#include <time.h>
/* Backup definition of SLIST_ENTRY on mingw winnt.h */
# ifdef SLIST_ENTRY
#  pragma push_macro("SLIST_ENTRY")
#  undef SLIST_ENTRY
#  define POP_SLIST_ENTRY
# endif
# include <windows.h>
/* restore definition */
# ifdef POP_SLIST_ENTRY
#  undef SLIST_ENTRY
#  undef POP_SLIST_ENTRY
#  pragma pop_macro("SLIST_ENTRY")
# endif

/* Windows filetime has the same definition as UA_DateTime */
UA_DateTime
UA_DateTime_now(void) {
    FILETIME ft;
    SYSTEMTIME st;
    GetSystemTime(&st);
    SystemTimeToFileTime(&st, &ft);
    ULARGE_INTEGER ul;
    ul.LowPart = ft.dwLowDateTime;
    ul.HighPart = ft.dwHighDateTime;
    return (UA_DateTime)ul.QuadPart;
}

/* Credit to https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c */
UA_Int64
UA_DateTime_localTimeUtcOffset(void) {
    time_t rawtime = time(NULL);
    struct tm ptm;
#ifdef __CODEGEARC__
    gmtime_s(&rawtime, &ptm);
#else
    gmtime_s(&ptm, &rawtime);
#endif

    /* Request mktime() to look up dst in timezone database */
    ptm.tm_isdst = -1;
    time_t gmt = mktime(&ptm);

    return (UA_Int64) (difftime(rawtime, gmt) * UA_DATETIME_SEC);
}

UA_DateTime
UA_DateTime_nowMonotonic(void) {
    LARGE_INTEGER freq, ticks;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&ticks);
    UA_Double ticks2dt = UA_DATETIME_SEC / (UA_Double)freq.QuadPart;
    return (UA_DateTime)(ticks.QuadPart * ticks2dt);
}

#endif /* UA_ARCHITECTURE_WIN32 */

/**** amalgamated original file "/arch/common/timer.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */



_UA_BEGIN_DECLS

/* The timer is protected by its own mutex. The mutex is released before calling
 * into the callbacks. So the timer can be modified from the callbacks it is
 * executing. Also, the timer mutex can never lead to locking. Because the timer
 * mutex will be left without acquiring another mutex.
 *
 * Obviously, the timer must not be deleted from within one of its
 * callbacks. */

typedef struct UA_TimerEntry {
    ZIP_ENTRY(UA_TimerEntry) treeEntry;
    UA_TimerPolicy timerPolicy; /* Timer policy to handle cycle misses */
    UA_DateTime nextTime;       /* The next time when the callback is to be
                                 * executed */
    UA_DateTime interval;       /* Interval in 100ns resolution. If the
                                 * interval is zero, the callback is not
                                 * repeated and removed after execution. */
    UA_Callback cb;             /* This is also a sentinel value. If the
                                 * callback is NULL, then the entry is
                                 * marked for deletion. */
    void *application;
    void *data;

    ZIP_ENTRY(UA_TimerEntry) idTreeEntry;
    UA_UInt64 id;                            /* Id of the entry */
} UA_TimerEntry;

typedef ZIP_HEAD(UA_TimerTree, UA_TimerEntry) UA_TimerTree;
typedef ZIP_HEAD(UA_TimerIdTree, UA_TimerEntry) UA_TimerIdTree;

typedef struct {
    UA_TimerTree tree;     /* The root of the time-sorted tree */
    UA_TimerIdTree idTree; /* The root of the id-sorted tree */
    UA_UInt64 idCounter;   /* Generate unique identifiers. Identifiers are
                            * always above zero. */
#if UA_MULTITHREADING >= 100
    UA_Lock timerMutex;
#endif
} UA_Timer;

void
UA_Timer_init(UA_Timer *t);

UA_DateTime
UA_Timer_next(UA_Timer *t);

UA_StatusCode
UA_Timer_add(UA_Timer *t, UA_Callback callback,
             void *application, void *data, UA_Double interval_ms,
             UA_DateTime now, UA_DateTime *baseTime,
             UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId);

UA_StatusCode
UA_Timer_modify(UA_Timer *t, UA_UInt64 callbackId,
                UA_Double interval_ms, UA_DateTime now,
                UA_DateTime *baseTime, UA_TimerPolicy timerPolicy);

void
UA_Timer_remove(UA_Timer *t, UA_UInt64 callbackId);

UA_DateTime
UA_Timer_process(UA_Timer *t, UA_DateTime now);

void
UA_Timer_clear(UA_Timer *t);

_UA_END_DECLS


/**** amalgamated original file "/arch/common/timer.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


static enum ZIP_CMP
cmpDateTime(const UA_DateTime *a, const UA_DateTime *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

static enum ZIP_CMP
cmpId(const UA_UInt64 *a, const UA_UInt64 *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

ZIP_FUNCTIONS(UA_TimerTree, UA_TimerEntry, treeEntry, UA_DateTime, nextTime, cmpDateTime)
ZIP_FUNCTIONS(UA_TimerIdTree, UA_TimerEntry, idTreeEntry, UA_UInt64, id, cmpId)

static UA_DateTime
calculateNextTime(UA_DateTime currentTime, UA_DateTime baseTime,
                  UA_DateTime interval) {
    /* Take the difference between current and base time */
    UA_DateTime diffCurrentTimeBaseTime = currentTime - baseTime;

    /* Take modulo of the diff time with the interval. This is the duration we
     * are already "into" the current interval. Subtract it from (current +
     * interval) to get the next execution time. */
    UA_DateTime cycleDelay = diffCurrentTimeBaseTime % interval;

    /* Handle the special case where the baseTime is in the future */
    if(UA_UNLIKELY(cycleDelay < 0))
        cycleDelay += interval;

    return currentTime + interval - cycleDelay;
}

void
UA_Timer_init(UA_Timer *t) {
    memset(t, 0, sizeof(UA_Timer));
    UA_LOCK_INIT(&t->timerMutex);
}

/* Global variables, only used behind the mutex */
static UA_DateTime earliest, latest, adjustedNextTime;

static void *
findTimer2Batch(void *context, UA_TimerEntry *compare) {
    /* Invariance of ZIP_ITER_KEY  */
    UA_assert(compare->nextTime >= earliest && compare->nextTime <= latest);

    /* One-shot timers have interval == 0.
     * They cannot participate in the modulo-based batching check. */
    UA_TimerEntry *te = (UA_TimerEntry*)context;
    if(te->interval == 0 || compare->interval == 0)
        return NULL;

    /* Check if one interval is a multiple of the other */
    if(te->interval < compare->interval && compare->interval % te->interval != 0)
        return NULL;
    if(te->interval > compare->interval && te->interval % compare->interval != 0)
        return NULL;

    adjustedNextTime = compare->nextTime; /* Candidate found */

    /* Abort when a perfect match is found */
    return (te->interval == compare->interval) ? te : NULL;
}

/* Window-based comparison for batching */
static enum ZIP_CMP
cmpBatchWindow(const UA_DateTime *start, const UA_DateTime *nextTime) {
    if(*nextTime < *start)
        return ZIP_CMP_LESS;
    if(*nextTime > latest)
        return ZIP_CMP_MORE;
    return ZIP_CMP_EQ;
}

typedef ZIP_HEAD(UA_TimerTreeWindow, UA_TimerEntry) UA_TimerTreeWindow;

ZIP_FUNCTIONS(UA_TimerTreeWindow, UA_TimerEntry, treeEntry,
              UA_DateTime, nextTime, cmpBatchWindow)

/* Adjust the nextTime to batch cyclic callbacks. Look in an interval around the
 * original nextTime. Deviate from the original nextTime by at most 1/4 of the
 * interval and at most by 1s. */
static void
batchTimerEntry(UA_Timer *t, UA_TimerEntry *te) {
    if(te->timerPolicy != UA_TIMERPOLICY_CURRENTTIME)
        return;
    UA_DateTime deviate = te->interval / 4;
    if(deviate > UA_DATETIME_SEC)
        deviate = UA_DATETIME_SEC;
    earliest = te->nextTime - deviate;
    latest = te->nextTime + deviate;
    adjustedNextTime = te->nextTime;
    ZIP_ITER_KEY(UA_TimerTreeWindow, (UA_TimerTreeWindow*)&t->tree,
                 &earliest, findTimer2Batch, te);
    te->nextTime = adjustedNextTime;
}

/* Adding repeated callbacks: Add an entry with the "nextTime" timestamp in the
 * future. This will be picked up in the next iteration and inserted at the
 * correct place. So that the next execution takes place ät "nextTime". */
UA_StatusCode
UA_Timer_add(UA_Timer *t, UA_Callback callback,
             void *application, void *data, UA_Double interval_ms,
             UA_DateTime now, UA_DateTime *baseTime,
             UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId) {
    /* A callback method needs to be present */
    if(!callback)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The interval needs to be positive. The exception is for the "once" policy
     * where we allow baseTime + interval < now. Then the timer executes once in
     * the next processing iteration. */
    UA_DateTime interval = (UA_DateTime)(interval_ms * UA_DATETIME_MSEC);
    if(interval <= 0) {
        if(timerPolicy != UA_TIMERPOLICY_ONCE)
            return UA_STATUSCODE_BADINTERNALERROR;
        /* Ensure that (now + interval) == *baseTime for setting nextTime */
        if(baseTime) {
            interval = *baseTime - now;
            baseTime = NULL;
        }
    }

    /* Compute the first time for execution */
    UA_DateTime nextTime = (baseTime == NULL) ?
        now + interval : calculateNextTime(now, *baseTime, interval);

    /* Allocate the repeated callback structure */
    UA_TimerEntry *te = (UA_TimerEntry*)UA_malloc(sizeof(UA_TimerEntry));
    if(!te)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set the repeated callback */
    te->interval = interval;
    te->cb = callback;
    te->application = application;
    te->data = data;
    te->nextTime = nextTime;
    te->timerPolicy = timerPolicy;

    /* Insert into the timer */
    UA_LOCK(&t->timerMutex);

    /* Adjust the nextTime to batch cyclic callbacks */
    batchTimerEntry(t, te);

    te->id = ++t->idCounter;
    if(callbackId)
        *callbackId = te->id;
    ZIP_INSERT(UA_TimerTree, &t->tree, te);
    ZIP_INSERT(UA_TimerIdTree, &t->idTree, te);
    UA_UNLOCK(&t->timerMutex);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Timer_modify(UA_Timer *t, UA_UInt64 callbackId,
                UA_Double interval_ms, UA_DateTime now,
                UA_DateTime *baseTime, UA_TimerPolicy timerPolicy) {
    /* The interval needs to be positive. The exception is for the "once" policy
     * where we allow baseTime + interval < now. Then the timer executes once in
     * the next processing iteration. */
    UA_DateTime interval = (UA_DateTime)(interval_ms * UA_DATETIME_MSEC);
    if(interval <= 0) {
        if(timerPolicy != UA_TIMERPOLICY_ONCE)
            return UA_STATUSCODE_BADINTERNALERROR;
        /* Ensure that (now + interval) == *baseTime for setting nextTime */
        if(baseTime) {
            interval = *baseTime - now;
            baseTime = NULL;
        }
    }

    UA_LOCK(&t->timerMutex);

    /* Find timer entry based on id */
    UA_TimerEntry *te = ZIP_FIND(UA_TimerIdTree, &t->idTree, &callbackId);
    if(!te) {
        UA_UNLOCK(&t->timerMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* The entry is either in the timer tree or current processed. If
     * in-process, the entry is re-added to the timer-tree right after. */
    UA_Boolean processing = (ZIP_REMOVE(UA_TimerTree, &t->tree, te) == NULL);

    /* The nextTime must only be modified after ZIP_REMOVE. The logic is
     * identical to the creation of a new timer. */
    te->nextTime = (baseTime == NULL) ?
        now + interval : calculateNextTime(now, *baseTime, interval);
    te->interval = interval;
    te->timerPolicy = timerPolicy;

    /* Adjust the nextTime to batch cyclic callbacks */
    batchTimerEntry(t, te);

    if(processing)
        te->nextTime -= interval; /* adjust for re-adding after processing */
    else
        ZIP_INSERT(UA_TimerTree, &t->tree, te);

    UA_UNLOCK(&t->timerMutex);
    return UA_STATUSCODE_GOOD;
}

void
UA_Timer_remove(UA_Timer *t, UA_UInt64 callbackId) {
    UA_LOCK(&t->timerMutex);
    UA_TimerEntry *te = ZIP_FIND(UA_TimerIdTree, &t->idTree, &callbackId);
    if(!te) {
        UA_UNLOCK(&t->timerMutex);
        return;
    }

    /* The entry is either in the timer tree or in the process tree. If in the
     * process tree, leave a sentinel (callback == NULL) to delete it during
     * processing. Do not edit the process tree while iterating over it. */
    UA_Boolean processing = (ZIP_REMOVE(UA_TimerTree, &t->tree, te) == NULL);
    if(!processing) {
        ZIP_REMOVE(UA_TimerIdTree, &t->idTree, te);
        UA_free(te);
    } else {
        te->cb = NULL;
    }

    UA_UNLOCK(&t->timerMutex);
}

struct TimerProcessContext {
    UA_Timer *t;
    UA_DateTime now;
};

static void *
processEntryCallback(void *context, UA_TimerEntry *te) {
    struct TimerProcessContext *tpc = (struct TimerProcessContext*)context;
    UA_Timer *t = tpc->t;

    /* Execute the callback */
    if(te->cb) {
        te->cb(te->application, te->data);
    }

    /* Remove the entry if marked for deletion or a "once" policy */
    if(!te->cb || te->timerPolicy == UA_TIMERPOLICY_ONCE) {
        ZIP_REMOVE(UA_TimerIdTree, &t->idTree, te);
        UA_free(te);
        return NULL;
    }

    /* Set the time for the next regular execution */
    te->nextTime += te->interval;

    /* Handle the case where the execution "window" was missed. E.g. due to
     * congestion of the application or if the clock was shifted.
     *
     * If the timer policy is "CurrentTime", then there is at least the
     * interval between executions. This is used for Monitoreditems, for
     * which the spec says: The sampling interval indicates the fastest rate
     * at which the Server should sample its underlying source for data
     * changes. (Part 4, 5.12.1.2).
     *
     * Otherwise calculate the next execution time based on the original base
     * time. */
    if(te->nextTime < tpc->now) {
        te->nextTime = (te->timerPolicy == UA_TIMERPOLICY_CURRENTTIME) ?
            tpc->now + te->interval :
            calculateNextTime(tpc->now, te->nextTime, te->interval);
    }

    /* Insert back into the time-sorted tree */
    ZIP_INSERT(UA_TimerTree, &t->tree, te);
    return NULL;
}

UA_DateTime
UA_Timer_process(UA_Timer *t, UA_DateTime now) {
    UA_LOCK(&t->timerMutex);

    /* Move all entries <= now to the processTree */
    UA_TimerTree processTree;
    ZIP_INIT(&processTree);
    ZIP_UNZIP(UA_TimerTree, &t->tree, &now, &processTree, &t->tree);

    /* Consistency check. The smallest not-processed entry isn't ready. */
    UA_assert(!ZIP_MIN(UA_TimerTree, &t->tree) ||
              ZIP_MIN(UA_TimerTree, &t->tree)->nextTime > now);
        
    /* Iterate over the entries that need processing in-order. This also
     * moves them back to the regular time-ordered tree. */
    struct TimerProcessContext ctx;
    ctx.t = t;
    ctx.now = now;
    ZIP_ITER(UA_TimerTree, &processTree, processEntryCallback, &ctx);
        
    /* Compute the timestamp of the earliest next callback */
    UA_TimerEntry *first = ZIP_MIN(UA_TimerTree, &t->tree);
    UA_DateTime next = (first) ? first->nextTime : UA_INT64_MAX;
    UA_UNLOCK(&t->timerMutex);
    return next;
}

UA_DateTime
UA_Timer_next(UA_Timer *t) {
    UA_LOCK(&t->timerMutex);
    UA_TimerEntry *first = ZIP_MIN(UA_TimerTree, &t->tree);
    UA_DateTime next = (first) ? first->nextTime : UA_INT64_MAX;
    UA_UNLOCK(&t->timerMutex);
    return next;
}

static void *
freeEntryCallback(void *context, UA_TimerEntry *entry) {
    UA_free(entry);
    return NULL;
}

void
UA_Timer_clear(UA_Timer *t) {
    UA_LOCK(&t->timerMutex);

    ZIP_ITER(UA_TimerIdTree, &t->idTree, freeEntryCallback, NULL);
    t->tree.root = NULL;
    t->idTree.root = NULL;
    t->idCounter = 0;

    UA_UNLOCK(&t->timerMutex);

#if UA_MULTITHREADING >= 100
    UA_LOCK_DESTROY(&t->timerMutex);
#endif
}

/**** amalgamated original file "/arch/common/eventloop_common.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */



/* Utility definitions to be used in EventLoop implementations.
 * Not part of the public API. */

_UA_BEGIN_DECLS

/* Typing restrictions for key-value parameters */
typedef struct {
    UA_QualifiedName name;
    const UA_DataType *type;
    UA_Boolean required;
    UA_Boolean scalar;
    UA_Boolean array;
} UA_KeyValueRestriction;

UA_StatusCode
UA_KeyValueRestriction_validate(const UA_Logger *logger,
                                const char *logprefix,
                                const UA_KeyValueRestriction *restrictions,
                                size_t restrictionsSize,
                                const UA_KeyValueMap *map);

_UA_END_DECLS


/**** amalgamated original file "/arch/common/eventloop_common.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


UA_StatusCode
UA_KeyValueRestriction_validate(const UA_Logger *logger, const char *logprefix,
                                const UA_KeyValueRestriction *restrictions,
                                size_t restrictionsSize,
                                const UA_KeyValueMap *map) {
    for(size_t i = 0; i < restrictionsSize; i++) {
        const UA_KeyValueRestriction *r = &restrictions[i];
        const UA_Variant *val = UA_KeyValueMap_get(map, r->name);

        /* Value not present but required? */
        if(!val) {
            if(r->required) {
                UA_LOG_WARNING(logger, UA_LOGCATEGORY_EVENTLOOP,
                               "%s\t| Parameter %.*s required but not defined",
                               logprefix, (int)r->name.name.length, (char*)r->name.name.data);
                return UA_STATUSCODE_BADINTERNALERROR;
            }
            continue;
        }

        /* Type matches */
        if(val->type != r->type) {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_EVENTLOOP,
                           "%s\t| Parameter %.*s has the wrong type",
                           logprefix, (int)r->name.name.length, (char*)r->name.name.data);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        /* Scalar / array is allowed */
        UA_Boolean scalar = UA_Variant_isScalar(val);
        if(scalar && !r->scalar) {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_EVENTLOOP,
                           "%s\t| Parameter %.*s must not be scalar",
                           logprefix, (int)r->name.name.length, (char*)r->name.name.data);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        if(!scalar && !r->array) {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_EVENTLOOP,
                           "%s\t| Parameter %.*s must not be an array",
                           logprefix, (int)r->name.name.length, (char*)r->name.name.data);
            return UA_STATUSCODE_BADCONNECTIONREJECTED;
        }
    }

    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/arch/posix/eventloop_posix.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */




#if !defined(__QNX__)
#endif

#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP) || defined(UA_ARCHITECTURE_WIN32)

_UA_BEGIN_DECLS

#include <errno.h>

#if defined(UA_ARCHITECTURE_WIN32)

/*********************/
/* Win32 Definitions */
/*********************/

/* Disable some security warnings on MSVC */
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
#endif

/*---------------------*/
/* Network Definitions */
/*---------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <basetsd.h>

#ifndef _SSIZE_T_DEFINED
typedef SSIZE_T ssize_t;
#endif

#define UA_IPV6 1
#define UA_SOCKET SOCKET
#define UA_INVALID_SOCKET INVALID_SOCKET
#define UA_RESET_ERRNO do { } while(0)
#define UA_ERRNO WSAGetLastError()
#define UA_INTERRUPTED WSAEINTR
#define UA_AGAIN EAGAIN /* the same as wouldblock on nearly every system */
#define UA_INPROGRESS WSAEINPROGRESS
#define UA_WOULDBLOCK WSAEWOULDBLOCK
#define UA_CONNRESET WSAECONNRESET
#define UA_NOBUFS WSAENOBUFS
#define UA_MFILE WSAEMFILE
#define UA_POLLIN POLLRDNORM
#define UA_POLLOUT POLLWRNORM
#define UA_SHUT_RDWR SD_BOTH

#define UA_IS_TEMPORARY_ACCEPT_ERROR(err) \
    ((err) == UA_INTERRUPTED || (err) == UA_CONNRESET || (err) == UA_NOBUFS || (err) == UA_MFILE)

#define UA_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
    getnameinfo(sa, (socklen_t)salen, host, (DWORD)hostlen, serv, (DWORD)servlen, flags)
#define UA_poll(fds,nfds,timeout) WSAPoll((LPWSAPOLLFD)fds, nfds, timeout)
#define UA_send(sockfd, buf, len, flags) send(sockfd, buf, (int)(len), flags)
#define UA_recv(sockfd, buf, len, flags) recv(sockfd, buf, (int)(len), flags)
#define UA_sendto(sockfd, buf, len, flags, dest_addr, addrlen) \
    sendto(sockfd, (const char*)(buf), (int)(len), flags, dest_addr, (int) (addrlen))
#define UA_close closesocket
#define UA_select(nfds, readfds, writefds, exceptfds, timeout) \
    select((int)(nfds), readfds, writefds, exceptfds, timeout)
#define UA_connect(sockfd, addr, addrlen) connect(sockfd, addr, (int)(addrlen))
#define UA_getsockopt(sockfd, level, optname, optval, optlen) \
    getsockopt(sockfd, level, optname, (char*) (optval), optlen)
#define UA_setsockopt(sockfd, level, optname, optval, optlen) \
    setsockopt(sockfd, level, optname, (const char*) (optval), optlen)
#define UA_inet_pton InetPton
#define UA_socket socket
#define UA_bind bind
#define UA_recvfrom recvfrom
#define UA_accept accept
#define UA_listen listen
#define UA_shutdown shutdown
#define UA_getaddrinfo getaddrinfo
#define UA_freeaddrinfo freeaddrinfo
#define UA_inet_ntop inet_ntop
#define UA_getsockname getsockname
#define UA_gethostname gethostname

#if UA_IPV6
# define UA_if_nametoindex if_nametoindex

# include <iphlpapi.h>

#endif

#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) do { \
    char *errno_str = NULL; \
    FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
    NULL, WSAGetLastError(), \
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
    (LPSTR)&errno_str, 0, NULL); \
    LOG; \
    LocalFree(errno_str); \
} while (0)
#define UA_LOG_SOCKET_ERRNO_GAI_WRAP UA_LOG_SOCKET_ERRNO_WRAP

/* Fix redefinition of SLIST_ENTRY on mingw winnt.h */
#if !defined(_SYS_QUEUE_H_) && defined(SLIST_ENTRY)
# undef SLIST_ENTRY
#endif

/*---------------------------*/
/* File Handling Definitions */
/*---------------------------*/

#include <direct.h>
#include <minwindef.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/stat.h>

_UA_BEGIN_DECLS
char *
_UA_dirname_minimal(char *path);
_UA_END_DECLS

#define UA_STAT stat
#define UA_DIR DIR
#define UA_DIRENT dirent
#define UA_FILE FILE
#define UA_MODE uint16_t

#define UA_stat stat
#define UA_opendir opendir
#define UA_readdir readdir
#define UA_rewinddir rewinddir
#define UA_closedir closedir
#define UA_mkdir(path, mode) _mkdir(path)
#define UA_fopen fopen
#define UA_fread fread
#define UA_fwrite fwrite
#define UA_fseek fseek
#define UA_ftell ftell
#define UA_fclose fclose
#define UA_remove remove
#define UA_dirname _UA_dirname_minimal

#define UA_SEEK_END SEEK_END
#define UA_SEEK_SET SEEK_SET
#define UA_DT_REG DT_REG
#define UA_DT_DIR DT_DIR
#define UA_PATH_MAX MAX_PATH
#define UA_FILENAME_MAX FILENAME_MAX

#elif defined(UA_ARCHITECTURE_POSIX)

/*********************/
/* POSIX Definitions */
/*********************/

#include <time.h>

/*---------------------*/
/* Network Definitions */
/*---------------------*/

#include <sys/socket.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <net/if.h>
#include <poll.h>
#include <fcntl.h>
#include <unistd.h>
#include <ifaddrs.h>

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(BSD)
#  include <sys/socket.h>
# endif
#endif

#if defined (__APPLE__)
typedef int SOCKET;
#endif

#define UA_IPV6 1
#define UA_SOCKET int
#define UA_INVALID_SOCKET -1
#define UA_RESET_ERRNO do { errno = 0; } while(0)
#define UA_ERRNO errno
#define UA_INTERRUPTED EINTR
#define UA_AGAIN EAGAIN /* the same as wouldblock on nearly every system */
#define UA_INPROGRESS EINPROGRESS
#define UA_WOULDBLOCK EWOULDBLOCK
#define UA_CONNABORTED ECONNABORTED
#define UA_MFILE EMFILE
#define UA_NFILE ENFILE
#define UA_NOBUFS ENOBUFS
#define UA_POLLIN POLLIN
#define UA_POLLOUT POLLOUT
#define UA_SHUT_RDWR SHUT_RDWR

#define UA_IS_TEMPORARY_ACCEPT_ERROR(err) \
    ((err) == UA_INTERRUPTED || (err) == UA_CONNABORTED || (err) == UA_MFILE || (err) == UA_NFILE || (err) == UA_NOBUFS)

#define UA_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
    getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
#define UA_poll poll
#define UA_send send
#define UA_recv recv
#define UA_sendto sendto
#define UA_close close
#define UA_select select
#define UA_connect connect
#define UA_getsockopt getsockopt
#define UA_setsockopt setsockopt
#define UA_inet_pton inet_pton
#define UA_if_nametoindex if_nametoindex
#define UA_socket socket
#define UA_bind bind
#define UA_recvfrom recvfrom
#define UA_accept accept
#define UA_listen listen
#define UA_shutdown shutdown
#define UA_getaddrinfo getaddrinfo
#define UA_freeaddrinfo freeaddrinfo
#define UA_inet_ntop inet_ntop
#define UA_getsockname getsockname
#define UA_gethostname gethostname

#define UA_clean_errno(STR_FUN) \
    (errno == 0 ? (char*) "None" : (STR_FUN)(errno))
#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) \
    do { char *errno_str = UA_clean_errno(strerror); LOG; errno = 0; } while (0)
#define UA_LOG_SOCKET_ERRNO_GAI_WRAP(LOG) \
    do { const char *errno_str = UA_clean_errno(gai_strerror); LOG; errno = 0; } while (0)

/* epoll_pwait returns bogus data with the tc compiler */
#if defined(__linux__) && !defined(__TINYC__)
# define UA_HAVE_EPOLL
# include <sys/epoll.h>
#endif

/*---------------------------*/
/* File Handling Definitions */
/*---------------------------*/

#include <dirent.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#ifdef __linux__
# include <sys/inotify.h>
#endif /* __linux__ */
#include <sys/stat.h>

#ifndef __ANDROID__
#ifndef __APPLE__
#include <bits/stdio_lim.h>
#endif /* !__APPLE__ */
#endif /* !__ANDROID__ */

#define UA_STAT stat
#define UA_DIR DIR
#define UA_DIRENT dirent
#define UA_FILE FILE
#define UA_MODE mode_t

#define UA_stat stat
#define UA_opendir opendir
#define UA_readdir readdir
#define UA_rewinddir rewinddir
#define UA_closedir closedir
#define UA_mkdir mkdir
#define UA_fopen fopen
#define UA_fread fread
#define UA_fwrite fwrite
#define UA_fseek fseek
#define UA_ftell ftell
#define UA_fclose fclose
#define UA_remove remove
#define UA_dirname dirname

#define UA_SEEK_END SEEK_END
#define UA_SEEK_SET SEEK_SET
#define UA_DT_REG DT_REG
#define UA_DT_DIR DT_DIR
#define UA_PATH_MAX PATH_MAX
#define UA_FILENAME_MAX FILENAME_MAX

#endif

/***********************/
/* General Definitions */
/***********************/

#define UA_MAXBACKLOG 100
#define UA_MAXHOSTNAME_LENGTH 256
#define UA_MAXPORTSTR_LENGTH 6

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0
#endif

/* POSIX events are based on sockets / file descriptors. The EventSources can
 * register their fd in the EventLoop so that they are considered by the
 * EventLoop dropping into "poll" to wait for events. */

/* TODO: Move the macro-forest from /arch/<arch>/ua_architecture.h */

#define UA_FD UA_SOCKET
#define UA_INVALID_FD UA_INVALID_SOCKET

struct UA_RegisteredFD;
typedef struct UA_RegisteredFD UA_RegisteredFD;

/* Bitmask to be used for the UA_FDCallback event argument */
#define UA_FDEVENT_IN 1
#define UA_FDEVENT_OUT 2
#define UA_FDEVENT_ERR 4

typedef void (*UA_FDCallback)(UA_EventSource *es, UA_RegisteredFD *rfd, short event);

struct UA_RegisteredFD {
    UA_DelayedCallback dc; /* Used for async closing. Must be the first member
                            * because the rfd is freed by the delayed callback
                            * mechanism. */

    ZIP_ENTRY(UA_RegisteredFD) zipPointers; /* Register FD in the EventSource */
    UA_FD fd;
    short listenEvents; /* UA_FDEVENT_IN | UA_FDEVENT_OUT*/

    /* Information to reopen listen socket */
    UA_String hostname;
    UA_UInt16 port;
    UA_Boolean reuseaddr;

    UA_EventSource *es; /* Backpointer to the EventSource */
    UA_FDCallback eventSourceCB;
};

enum ZIP_CMP cmpFD(const UA_FD *a, const UA_FD *b);
typedef ZIP_HEAD(UA_FDTree, UA_RegisteredFD) UA_FDTree;
ZIP_FUNCTIONS(UA_FDTree, UA_RegisteredFD, zipPointers, UA_FD, fd, cmpFD)

typedef struct UA_DeregisteredListenFD {
    LIST_ENTRY(UA_DeregisteredListenFD) pointers;
    UA_RegisteredFD *listenFd;
} UA_DeregisteredListenFD;

typedef LIST_HEAD(UA_DeregisteredListenFDList, UA_DeregisteredListenFD) UA_DeregisteredListenFDList;

/* All ConnectionManager in the POSIX EventLoop can be cast to
 * UA_ConnectionManagerPOSIX. They carry a sorted tree of their open
 * sockets/file-descriptors. */
typedef struct {
    UA_ConnectionManager cm;

    /* Statically allocated buffers */
    UA_ByteString rxBuffer;
    UA_ByteString txBuffer;

    /* Sorted tree of the FDs */
    size_t fdsSize;
    UA_FDTree fds;

    /* Closed listening sockets queued for later reopening */
    UA_DeregisteredListenFDList listenFDs;
} UA_POSIXConnectionManager;

typedef struct {
    UA_EventLoop eventLoop;

    /* Timer */
    UA_Timer timer;

    /* Singly-linked FIFO queue (lock-free multi-producer single-consumer) of
     * delayed callbacks. Insertion happens by chasing the tail-pointer. We
     * "check out" the current queue and reset by switching the tail to the
     * alternative head-pointer.
     *
     * This could be a simple singly-linked list. But we want to do in-order
     * processing so we can wait until the worker jobs already in the queue get
     * finished before.
     *
     * The currently unused head gets marked with the 0x01 sentinel. */
    UA_DelayedCallback *delayedHead1;
    UA_DelayedCallback *delayedHead2;
    UA_DelayedCallback **delayedTail;

    /* Flag determining whether the eventloop is currently within the
     * "run" method */
    volatile UA_Boolean executing;

    /* Indicates that the maximum number of sockets has been reached.
     * All listening sockets will be closed. */
    UA_Boolean maxSocketsLimitReached;

    /* Clocks for the eventloop's time domain */
    UA_Int32 clockSource;
    UA_Int32 clockSourceMonotonic;

#if defined(UA_HAVE_EPOLL)
    UA_FD epollfd;
#else
    UA_RegisteredFD **fds;
    size_t fdsSize;
#endif

    /* Self-pipe to cancel blocking wait */
    UA_FD selfpipe[2]; /* 0: read, 1: write */

#if UA_MULTITHREADING >= 100
    UA_Lock elMutex;
#endif
} UA_EventLoopPOSIX;

/* The following functions differ between epoll and normal select */

/* Register to start receiving events */
UA_StatusCode
UA_EventLoopPOSIX_registerFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd);

/* Modify the events that the fd listens on */
UA_StatusCode
UA_EventLoopPOSIX_modifyFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd);

/* Deregister but do not close the fd. No further events are received. */
void
UA_EventLoopPOSIX_deregisterFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd);

UA_StatusCode
UA_EventLoopPOSIX_pollFDs(UA_EventLoopPOSIX *el, UA_DateTime listenTimeout);

/* Helper functions across EventSources */

UA_StatusCode
UA_EventLoopPOSIX_allocateStaticBuffers(UA_POSIXConnectionManager *pcm);

UA_StatusCode
UA_EventLoopPOSIX_allocNetworkBuffer(UA_ConnectionManager *cm,
                                     uintptr_t connectionId,
                                     UA_ByteString *buf,
                                     size_t bufSize);

void
UA_EventLoopPOSIX_freeNetworkBuffer(UA_ConnectionManager *cm,
                                    uintptr_t connectionId,
                                    UA_ByteString *buf);

/* Set the socket non-blocking. If the listen-socket is nonblocking, incoming
 * connections inherit this state. */
UA_StatusCode
UA_EventLoopPOSIX_setNonBlocking(UA_FD sockfd);

/* Don't have the socket create interrupt signals */
UA_StatusCode
UA_EventLoopPOSIX_setNoSigPipe(UA_FD sockfd);

/* Enables sharing of the same listening address on different sockets */
UA_StatusCode
UA_EventLoopPOSIX_setReusable(UA_FD sockfd);

/* Windows has no pipes. Use a local TCP connection for the self-pipe trick.
 * https://stackoverflow.com/a/3333565 */
#if defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__)
int UA_EventLoopPOSIX_pipe(SOCKET fds[2]);
#elif defined(__QNX__)
int UA_EventLoopPOSIX_pipe(int fds[2]);
#else
# define UA_EventLoopPOSIX_pipe(fds) pipe2(fds, O_NONBLOCK)
#endif

/* Cancel the current _run by sending to the self-pipe */
void
UA_EventLoopPOSIX_cancel(UA_EventLoopPOSIX *el);

void
UA_EventLoopPOSIX_addDelayedCallback(UA_EventLoop *public_el,
                                     UA_DelayedCallback *dc);

_UA_END_DECLS

#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */


/**** amalgamated original file "/arch/posix/eventloop_posix.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */


#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP) || defined(UA_ARCHITECTURE_WIN32)

/*********/
/* Timer */
/*********/

static UA_DateTime
UA_EventLoopPOSIX_nextTimer(UA_EventLoop *public_el) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    if(el->delayedHead1 > (UA_DelayedCallback *)0x01 ||
       el->delayedHead2 > (UA_DelayedCallback *)0x01)
        return el->eventLoop.dateTime_nowMonotonic(&el->eventLoop);
    return UA_Timer_next(&el->timer);
}

static UA_StatusCode
UA_EventLoopPOSIX_addTimer(UA_EventLoop *public_el, UA_Callback cb,
                           void *application, void *data, UA_Double interval_ms,
                           UA_DateTime *baseTime, UA_TimerPolicy timerPolicy,
                           UA_UInt64 *callbackId) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    return UA_Timer_add(&el->timer, cb, application, data, interval_ms,
                        public_el->dateTime_nowMonotonic(public_el),
                        baseTime, timerPolicy, callbackId);
}

static UA_StatusCode
UA_EventLoopPOSIX_modifyTimer(UA_EventLoop *public_el,
                              UA_UInt64 callbackId,
                              UA_Double interval_ms,
                              UA_DateTime *baseTime,
                              UA_TimerPolicy timerPolicy) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    return UA_Timer_modify(&el->timer, callbackId, interval_ms,
                           public_el->dateTime_nowMonotonic(public_el),
                           baseTime, timerPolicy);
}

static void
UA_EventLoopPOSIX_removeTimer(UA_EventLoop *public_el,
                              UA_UInt64 callbackId) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    UA_Timer_remove(&el->timer, callbackId);
}

void
UA_EventLoopPOSIX_addDelayedCallback(UA_EventLoop *public_el,
                                     UA_DelayedCallback *dc) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    dc->next = NULL;

    /* el->delayedTail points either to prev->next or to the head.
     * We need to update two locations:
     * 1: el->delayedTail = &dc->next;
     * 2: *oldtail = dc; (equal to &dc->next)
     *
     * Once we have (1), we "own" the previous-to-last entry. No need to worry
     * about (2), we can adjust it with a delay. This makes the queue
     * "eventually consistent". */
    UA_DelayedCallback **oldtail = (UA_DelayedCallback**)
        UA_atomic_xchg((void**)&el->delayedTail, &dc->next);
    UA_atomic_xchg((void**)oldtail, &dc->next);
}

/* Resets the delayed queue and returns the previous head and tail */
static void
resetDelayedQueue(UA_EventLoopPOSIX *el, UA_DelayedCallback **oldHead,
                  UA_DelayedCallback **oldTail) {
    if(el->delayedHead1 <= (UA_DelayedCallback *)0x01 &&
       el->delayedHead2 <= (UA_DelayedCallback *)0x01)
        return; /* The queue is empty */

    UA_Boolean active1 = (el->delayedHead1 != (UA_DelayedCallback*)0x01);
    UA_DelayedCallback **activeHead = (active1) ? &el->delayedHead1 : &el->delayedHead2;
    UA_DelayedCallback **inactiveHead = (active1) ? &el->delayedHead2 : &el->delayedHead1;

    /* Switch active/inactive by resetting the sentinel values. The (old) active
     * head points to an element which we return. Parallel threads continue to
     * add elements to the queue "below" the first element. */
    UA_atomic_xchg((void**)inactiveHead, NULL);
    *oldHead = (UA_DelayedCallback *)
        UA_atomic_xchg((void**)activeHead, (void*)0x01);

    /* Make the tail point to the (new) active head. Return the value of last
     * tail. When iterating over the queue elements, we need to find this tail
     * as the last element. If we find a NULL next-pointer before hitting the
     * tail spinlock until the pointer updates (eventually consistent). */
    *oldTail = (UA_DelayedCallback*)
        UA_atomic_xchg((void**)&el->delayedTail, inactiveHead);
}

static void
UA_EventLoopPOSIX_removeDelayedCallback(UA_EventLoop *public_el,
                                        UA_DelayedCallback *dc) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    UA_LOCK(&el->elMutex);

    /* Reset and get the old head and tail */
    UA_DelayedCallback *cur = NULL, *tail = NULL;
    resetDelayedQueue(el, &cur, &tail);

    /* Loop until we reach the tail (or head and tail are both NULL) */
    UA_DelayedCallback *next;
    for(; cur; cur = next) {
        /* Spin-loop until the next-pointer of cur is updated.
         * The element pointed to by tail must appear eventually. */
        next = cur->next;
        while(!next && cur != tail)
            next = (UA_DelayedCallback *)UA_atomic_load((void**)&cur->next);
        if(cur == dc)
            continue;
        UA_EventLoopPOSIX_addDelayedCallback(public_el, cur);
    }

    UA_UNLOCK(&el->elMutex);
}

static void
processDelayed(UA_EventLoopPOSIX *el) {
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Process delayed callbacks");

    UA_LOCK_ASSERT(&el->elMutex);

    /* Reset and get the old head and tail */
    UA_DelayedCallback *dc = NULL, *tail = NULL;
    resetDelayedQueue(el, &dc, &tail);

    /* Loop until we reach the tail (or head and tail are both NULL) */
    UA_DelayedCallback *next;
    for(; dc; dc = next) {
        next = dc->next;
        while(!next && dc != tail)
            next = (UA_DelayedCallback *)UA_atomic_load((void**)&dc->next);
        if(!dc->callback)
            continue;
        dc->callback(dc->application, dc->context);
    }
}

/***********************/
/* EventLoop Lifecycle */
/***********************/

static UA_StatusCode
UA_EventLoopPOSIX_start(UA_EventLoopPOSIX *el) {
    UA_LOCK(&el->elMutex);

    if(el->eventLoop.state != UA_EVENTLOOPSTATE_FRESH &&
       el->eventLoop.state != UA_EVENTLOOPSTATE_STOPPED) {
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Starting the EventLoop");

    /* Setting custom clock source */
    const UA_Int32 *cs = (const UA_Int32*)
        UA_KeyValueMap_getScalar(&el->eventLoop.params,
                                 UA_QUALIFIEDNAME(0, "clock-source"),
                                 &UA_TYPES[UA_TYPES_INT32]);
    if(cs)
        el->clockSource = *cs;

    const UA_Int32 *csm = (const UA_Int32*)
        UA_KeyValueMap_getScalar(&el->eventLoop.params,
                                 UA_QUALIFIEDNAME(0, "clock-source-monotonic"),
                                 &UA_TYPES[UA_TYPES_INT32]);
    if(csm) {
        if(el->clockSourceMonotonic != *csm && el->timer.idTree.root) {
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Eventloop\t| Setting a different monotonic clock, ",
                           "but existing timers have been registered with a "
                           "different clock source");
        }
        el->clockSourceMonotonic = *csm;
    }

#if !defined(UA_ARCHITECTURE_POSIX)
    if(cs || csm) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Eventloop\t| Setting a different clock source ",
                       "not supported for this architecture");
    }
#endif

    /* Create the self-pipe */
    int err = UA_EventLoopPOSIX_pipe(el->selfpipe);
    if(err != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "Eventloop\t| Could not create the self-pipe (%s)",
                          errno_str));
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create the epoll socket */
#ifdef UA_HAVE_EPOLL
    el->epollfd = epoll_create1(0);
    if(el->epollfd == -1) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "Eventloop\t| Could not create the epoll socket (%s)",
                          errno_str));
        UA_close(el->selfpipe[0]);
        UA_close(el->selfpipe[1]);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* epoll always listens on the self-pipe. This is the only epoll_event that
     * has a NULL data pointer. */
    struct epoll_event event;
    memset(&event, 0, sizeof(struct epoll_event));
    event.events = EPOLLIN;
    err = epoll_ctl(el->epollfd, EPOLL_CTL_ADD, el->selfpipe[0], &event);
    if(err != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "Eventloop\t| Could not register the self-pipe for epoll (%s)",
                          errno_str));
        UA_close(el->selfpipe[0]);
        UA_close(el->selfpipe[1]);
        close(el->epollfd);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
#endif

    /* Start the EventSources */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_EventSource *es = el->eventLoop.eventSources;
    while(es) {
        res |= es->start(es);
        es = es->next;
    }

    /* Dirty-write the state that is const "from the outside" */
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
        UA_EVENTLOOPSTATE_STARTED;

    UA_UNLOCK(&el->elMutex);
    return res;
}

static void
checkClosed(UA_EventLoopPOSIX *el) {
    UA_LOCK_ASSERT(&el->elMutex);

    UA_EventSource *es = el->eventLoop.eventSources;
    while(es) {
        if(es->state != UA_EVENTSOURCESTATE_STOPPED)
            return;
        es = es->next;
    }

    /* Not closed until all delayed callbacks are processed */
    if(el->delayedHead1 != NULL && el->delayedHead2 != NULL)
        return;

    /* Close the self-pipe when everything else is done */
    UA_close(el->selfpipe[0]);
    UA_close(el->selfpipe[1]);

    /* Dirty-write the state that is const "from the outside" */
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
        UA_EVENTLOOPSTATE_STOPPED;

    /* Close the epoll/IOCP socket once all EventSources have shut down */
#ifdef UA_HAVE_EPOLL
    UA_close(el->epollfd);
#endif

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "The EventLoop has stopped");
}

static void
UA_EventLoopPOSIX_stop(UA_EventLoopPOSIX *el) {
    UA_LOCK(&el->elMutex);

    if(el->eventLoop.state != UA_EVENTLOOPSTATE_STARTED) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "The EventLoop is not running, cannot be stopped");
        UA_UNLOCK(&el->elMutex);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Stopping the EventLoop");

    /* Set to STOPPING to prevent "normal use" */
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
        UA_EVENTLOOPSTATE_STOPPING;

    /* Stop all event sources (asynchronous) */
    UA_EventSource *es = el->eventLoop.eventSources;
    for(; es; es = es->next) {
        if(es->state == UA_EVENTSOURCESTATE_STARTING ||
           es->state == UA_EVENTSOURCESTATE_STARTED) {
            es->stop(es);
        }
    }

    /* Set to STOPPED if all EventSources are STOPPED */
    checkClosed(el);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
UA_EventLoopPOSIX_run(UA_EventLoopPOSIX *el, UA_UInt32 timeout) {
    UA_LOCK(&el->elMutex);

    if(el->executing) {
        UA_LOG_ERROR(el->eventLoop.logger,
                     UA_LOGCATEGORY_EVENTLOOP,
                     "Cannot run EventLoop from the run method itself");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    el->executing = true;

    if(el->eventLoop.state == UA_EVENTLOOPSTATE_FRESH ||
       el->eventLoop.state == UA_EVENTLOOPSTATE_STOPPED) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Cannot run a stopped EventLoop");
        el->executing = false;
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Iterate the EventLoop");

    /* Process cyclic callbacks */
    UA_DateTime dateBefore =
        el->eventLoop.dateTime_nowMonotonic(&el->eventLoop);

    UA_DateTime dateNext = UA_Timer_process(&el->timer, dateBefore);

    /* Process delayed callbacks here:
     * - Removes closed sockets already here instead of polling them again.
     * - The timeout for polling is selected to be ready in time for the next
     *   cyclic callback. So we want to do little work between the timeout
     *   running out and executing the due cyclic callbacks. */
    processDelayed(el);

    /* A delayed callback could create another delayed callback (or re-add
     * itself). In that case we don't want to wait (indefinitely) for an event
     * to happen. Process queued events but don't sleep. Then process the
     * delayed callbacks in the next iteration. */
    if(el->delayedHead1 != NULL && el->delayedHead2 != NULL)
        timeout = 0;

    /* Compute the remaining time */
    UA_DateTime maxDate = dateBefore + (timeout * UA_DATETIME_MSEC);
    if(dateNext > maxDate)
        dateNext = maxDate;
    UA_DateTime listenTimeout =
        dateNext - el->eventLoop.dateTime_nowMonotonic(&el->eventLoop);
    if(listenTimeout < 0)
        listenTimeout = 0;

    /* Listen on the active file-descriptors (sockets) from the
     * ConnectionManagers */
    UA_StatusCode rv = UA_EventLoopPOSIX_pollFDs(el, listenTimeout);

    /* Check if the last EventSource was successfully stopped */
    if(el->eventLoop.state == UA_EVENTLOOPSTATE_STOPPING)
        checkClosed(el);

    el->executing = false;
    UA_UNLOCK(&el->elMutex);
    return rv;
}

/*****************************/
/* Registering Event Sources */
/*****************************/

static UA_StatusCode
UA_EventLoopPOSIX_registerEventSource(UA_EventLoopPOSIX *el,
                                      UA_EventSource *es) {
    UA_LOCK(&el->elMutex);

    /* Already registered? */
    if(es->state != UA_EVENTSOURCESTATE_FRESH) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "Cannot register the EventSource \"%.*s\": "
                     "already registered",
                     (int)es->name.length, (char*)es->name.data);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Add to linked list */
    es->next = el->eventLoop.eventSources;
    el->eventLoop.eventSources = es;

    es->eventLoop = &el->eventLoop;
    es->state = UA_EVENTSOURCESTATE_STOPPED;

    /* Start if the entire EventLoop is started */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(el->eventLoop.state == UA_EVENTLOOPSTATE_STARTED)
        res = es->start(es);

    UA_UNLOCK(&el->elMutex);
    return res;
}

static UA_StatusCode
UA_EventLoopPOSIX_deregisterEventSource(UA_EventLoopPOSIX *el,
                                        UA_EventSource *es) {
    UA_LOCK(&el->elMutex);

    if(es->state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Cannot deregister the EventSource %.*s: "
                       "Has to be stopped first",
                       (int)es->name.length, es->name.data);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Remove from the linked list */
    UA_EventSource **s = &el->eventLoop.eventSources;
    while(*s) {
        if(*s == es) {
            *s = es->next;
            break;
        }
        s = &(*s)->next;
    }

    /* Set the state to non-registered */
    es->state = UA_EVENTSOURCESTATE_FRESH;

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

/***************/
/* Time Domain */
/***************/

static UA_DateTime
UA_EventLoopPOSIX_DateTime_now(UA_EventLoop *el) {
#if defined(UA_ARCHITECTURE_POSIX)
    UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
    struct timespec ts;
    int res = clock_gettime(pel->clockSource, &ts);
    if(UA_UNLIKELY(res != 0))
        return 0;
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#else
    return UA_DateTime_now();
#endif
}

static UA_DateTime
UA_EventLoopPOSIX_DateTime_nowMonotonic(UA_EventLoop *el) {
#if defined(UA_ARCHITECTURE_POSIX)
    UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
    struct timespec ts;
    int res = clock_gettime(pel->clockSourceMonotonic, &ts);
    if(UA_UNLIKELY(res != 0))
        return 0;
    /* Also add the unix epoch for the monotonic clock. So we get a "normal"
     * output when a "normal" source is configured. */
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#else
    return UA_DateTime_nowMonotonic();
#endif
}

static UA_Int64
UA_EventLoopPOSIX_DateTime_localTimeUtcOffset(UA_EventLoop *el) {
    /* TODO: Fix for custom clock sources */
    return UA_DateTime_localTimeUtcOffset();
}

/*************************/
/* Initialize and Delete */
/*************************/

static UA_StatusCode
UA_EventLoopPOSIX_free(UA_EventLoopPOSIX *el) {
    UA_LOCK(&el->elMutex);

    /* Check if the EventLoop can be deleted */
    if(el->eventLoop.state != UA_EVENTLOOPSTATE_STOPPED &&
       el->eventLoop.state != UA_EVENTLOOPSTATE_FRESH) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Cannot delete a running EventLoop");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Deregister and delete all the EventSources */
    while(el->eventLoop.eventSources) {
        UA_EventSource *es = el->eventLoop.eventSources;
        UA_EventLoopPOSIX_deregisterEventSource(el, es);
        es->free(es);
    }

    /* Remove the repeated timed callbacks */
    UA_Timer_clear(&el->timer);

    /* Process remaining delayed callbacks */
    processDelayed(el);

#ifdef UA_ARCHITECTURE_WIN32
    /* Stop the Windows networking subsystem */
    WSACleanup();
#endif

    UA_KeyValueMap_clear(&el->eventLoop.params);

    /* Clean up */
    UA_UNLOCK(&el->elMutex);
    UA_LOCK_DESTROY(&el->elMutex);
    UA_free(el);
    return UA_STATUSCODE_GOOD;
}

static void
UA_EventLoopPOSIX_lock(UA_EventLoop *public_el) {
    UA_LOCK(&((UA_EventLoopPOSIX*)public_el)->elMutex);
}
static void
UA_EventLoopPOSIX_unlock(UA_EventLoop *public_el) {
    UA_UNLOCK(&((UA_EventLoopPOSIX*)public_el)->elMutex);
}

UA_EventLoop *
UA_EventLoop_new_POSIX(const UA_Logger *logger) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)
        UA_calloc(1, sizeof(UA_EventLoopPOSIX));
    if(!el)
        return NULL;

    UA_LOCK_INIT(&el->elMutex);
    UA_Timer_init(&el->timer);

    /* Initialize the queue */
    el->delayedTail = &el->delayedHead1;
    el->delayedHead2 = (UA_DelayedCallback*)0x01; /* sentinel value */

#ifdef UA_ARCHITECTURE_WIN32
    /* Start the WSA networking subsystem on Windows */
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif

    /* Set the public EventLoop content */
    el->eventLoop.logger = logger;

    /* Initialize the clock source to the default */
#if defined(UA_ARCHITECTURE_POSIX)
    el->clockSource = CLOCK_REALTIME;
# ifdef CLOCK_MONOTONIC_RAW
    el->clockSourceMonotonic = CLOCK_MONOTONIC_RAW;
# else
    el->clockSourceMonotonic = CLOCK_MONOTONIC;
# endif
#endif

    /* Set the method pointers for the interface */
    el->eventLoop.start = (UA_StatusCode (*)(UA_EventLoop*))UA_EventLoopPOSIX_start;
    el->eventLoop.stop = (void (*)(UA_EventLoop*))UA_EventLoopPOSIX_stop;
    el->eventLoop.free = (UA_StatusCode (*)(UA_EventLoop*))UA_EventLoopPOSIX_free;
    el->eventLoop.run = (UA_StatusCode (*)(UA_EventLoop*, UA_UInt32))UA_EventLoopPOSIX_run;
    el->eventLoop.cancel = (void (*)(UA_EventLoop*))UA_EventLoopPOSIX_cancel;

    el->eventLoop.dateTime_now = UA_EventLoopPOSIX_DateTime_now;
    el->eventLoop.dateTime_nowMonotonic =
        UA_EventLoopPOSIX_DateTime_nowMonotonic;
    el->eventLoop.dateTime_localTimeUtcOffset =
        UA_EventLoopPOSIX_DateTime_localTimeUtcOffset;

    el->eventLoop.nextTimer = UA_EventLoopPOSIX_nextTimer;
    el->eventLoop.addTimer = UA_EventLoopPOSIX_addTimer;
    el->eventLoop.modifyTimer = UA_EventLoopPOSIX_modifyTimer;
    el->eventLoop.removeTimer = UA_EventLoopPOSIX_removeTimer;
    el->eventLoop.addDelayedCallback = UA_EventLoopPOSIX_addDelayedCallback;
    el->eventLoop.removeDelayedCallback = UA_EventLoopPOSIX_removeDelayedCallback;

    el->eventLoop.registerEventSource =
        (UA_StatusCode (*)(UA_EventLoop*, UA_EventSource*))
        UA_EventLoopPOSIX_registerEventSource;
    el->eventLoop.deregisterEventSource =
        (UA_StatusCode (*)(UA_EventLoop*, UA_EventSource*))
        UA_EventLoopPOSIX_deregisterEventSource;

    el->eventLoop.lock = UA_EventLoopPOSIX_lock;
    el->eventLoop.unlock = UA_EventLoopPOSIX_unlock;

    return &el->eventLoop;
}

/***************************/
/* Network Buffer Handling */
/***************************/

UA_StatusCode
UA_EventLoopPOSIX_allocNetworkBuffer(UA_ConnectionManager *cm,
                                     uintptr_t connectionId,
                                     UA_ByteString *buf,
                                     size_t bufSize) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(pcm->txBuffer.length == 0)
        return UA_ByteString_allocBuffer(buf, bufSize);
    if(pcm->txBuffer.length < bufSize)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *buf = pcm->txBuffer;
    buf->length = bufSize;
    return UA_STATUSCODE_GOOD;
}

void
UA_EventLoopPOSIX_freeNetworkBuffer(UA_ConnectionManager *cm,
                                    uintptr_t connectionId,
                                    UA_ByteString *buf) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(pcm->txBuffer.data == buf->data)
        UA_ByteString_init(buf);
    else
        UA_ByteString_clear(buf);
}

UA_StatusCode
UA_EventLoopPOSIX_allocateStaticBuffers(UA_POSIXConnectionManager *pcm) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
    const UA_UInt32 *configRxBufSize = (const UA_UInt32 *)
        UA_KeyValueMap_getScalar(&pcm->cm.eventSource.params,
                                 UA_QUALIFIEDNAME(0, "recv-bufsize"),
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(configRxBufSize)
        rxBufSize = *configRxBufSize;
    if(pcm->rxBuffer.length != rxBufSize) {
        UA_ByteString_clear(&pcm->rxBuffer);
        res = UA_ByteString_allocBuffer(&pcm->rxBuffer, rxBufSize);
    }

    const UA_UInt32 *txBufSize = (const UA_UInt32 *)
        UA_KeyValueMap_getScalar(&pcm->cm.eventSource.params,
                                 UA_QUALIFIEDNAME(0, "send-bufsize"),
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(txBufSize && pcm->txBuffer.length != *txBufSize) {
        UA_ByteString_clear(&pcm->txBuffer);
        res |= UA_ByteString_allocBuffer(&pcm->txBuffer, *txBufSize);
    }
    return res;
}

/******************/
/* Socket Options */
/******************/

enum ZIP_CMP
cmpFD(const UA_FD *a, const UA_FD *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

UA_StatusCode
UA_EventLoopPOSIX_setNonBlocking(UA_FD sockfd) {
#ifndef UA_ARCHITECTURE_WIN32
    int opts = fcntl(sockfd, F_GETFL);
    if(opts < 0 || fcntl(sockfd, F_SETFL, opts | O_NONBLOCK) < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
#else
    u_long iMode = 1;
    if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR)
        return UA_STATUSCODE_BADINTERNALERROR;
#endif
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_setNoSigPipe(UA_FD sockfd) {
#ifdef SO_NOSIGPIPE
    int val = 1;
    int res = UA_setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
    if(res < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
#endif
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_setReusable(UA_FD sockfd) {
    int enableReuseVal = 1;
#ifndef UA_ARCHITECTURE_WIN32
    int res = UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                            (const char*)&enableReuseVal, sizeof(enableReuseVal));
    res |= UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
                            (const char*)&enableReuseVal, sizeof(enableReuseVal));
    return (res == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;
#else
    int res = UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                            (const char*)&enableReuseVal, sizeof(enableReuseVal));
    return (res == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;
#endif
}

/************************/
/* Select / epoll Logic */
/************************/

/* Re-arm the self-pipe socket for the next signal by reading from it */
static void
flushSelfPipe(UA_SOCKET s) {
    char buf[128];
#ifdef UA_ARCHITECTURE_WIN32
    recv(s, buf, 128, 0);
#else
    ssize_t i;
    do {
        i = read(s, buf, 128);
    } while(i > 0);
#endif
}

#if !defined(UA_HAVE_EPOLL)

UA_StatusCode
UA_EventLoopPOSIX_registerFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    UA_LOCK_ASSERT(&el->elMutex);
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Registering fd: %u", (unsigned)rfd->fd);

    /* Realloc */
    UA_RegisteredFD **fds_tmp = (UA_RegisteredFD**)
        UA_realloc(el->fds, sizeof(UA_RegisteredFD*) * (el->fdsSize + 1));
    if(!fds_tmp) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    el->fds = fds_tmp;

    /* Add to the last entry */
    el->fds[el->fdsSize] = rfd;
    el->fdsSize++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_modifyFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    /* Do nothing, it is enough if the data was changed in the rfd */
    UA_LOCK_ASSERT(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

void
UA_EventLoopPOSIX_deregisterFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    UA_LOCK_ASSERT(&el->elMutex);
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Unregistering fd: %u", (unsigned)rfd->fd);

    /* Find the entry */
    size_t i = 0;
    for(; i < el->fdsSize; i++) {
        if(el->fds[i] == rfd)
            break;
    }

    /* Not found? */
    if(i == el->fdsSize)
        return;

    if(el->fdsSize > 1) {
        /* Move the last entry in the ith slot and realloc. */
        el->fdsSize--;
        el->fds[i] = el->fds[el->fdsSize];
        UA_RegisteredFD **fds_tmp = (UA_RegisteredFD**)
            UA_realloc(el->fds, sizeof(UA_RegisteredFD*) * el->fdsSize);
        /* if realloc fails the fds are still in a correct state with
         * possibly lost memory, so failing silently here is ok */
        if(fds_tmp)
            el->fds = fds_tmp;
    } else {
        /* Remove the last entry */
        UA_free(el->fds);
        el->fds = NULL;
        el->fdsSize = 0;
    }
}

static UA_FD
setFDSets(UA_EventLoopPOSIX *el, fd_set *readset, fd_set *writeset, fd_set *errset) {
    UA_LOCK_ASSERT(&el->elMutex);

    FD_ZERO(readset);
    FD_ZERO(writeset);
    FD_ZERO(errset);

    /* Always listen on the read-end of the pipe */
    UA_FD highestfd = el->selfpipe[0];
    FD_SET(el->selfpipe[0], readset);

    for(size_t i = 0; i < el->fdsSize; i++) {
        UA_FD currentFD = el->fds[i]->fd;

        /* Add to the fd_sets */
        if(el->fds[i]->listenEvents & UA_FDEVENT_IN)
            FD_SET(currentFD, readset);
        if(el->fds[i]->listenEvents & UA_FDEVENT_OUT)
            FD_SET(currentFD, writeset);

        /* Always return errors */
        FD_SET(currentFD, errset);

        /* Highest fd? */
        if(currentFD > highestfd)
            highestfd = currentFD;
    }
    return highestfd;
}

UA_StatusCode
UA_EventLoopPOSIX_pollFDs(UA_EventLoopPOSIX *el, UA_DateTime listenTimeout) {
    UA_assert(listenTimeout >= 0);
    UA_LOCK_ASSERT(&el->elMutex);

    fd_set readset, writeset, errset;
    UA_FD highestfd = setFDSets(el, &readset, &writeset, &errset);

    /* Nothing to do? */
    if(highestfd == UA_INVALID_FD) {
        UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "No valid FDs for processing");
        return UA_STATUSCODE_GOOD;
    }

    struct timeval tmptv = {
#ifndef UA_ARCHITECTURE_WIN32
        (time_t)(listenTimeout / UA_DATETIME_SEC),
        (suseconds_t)((listenTimeout % UA_DATETIME_SEC) / UA_DATETIME_USEC)
#else
        (long)(listenTimeout / UA_DATETIME_SEC),
        (long)((listenTimeout % UA_DATETIME_SEC) / UA_DATETIME_USEC)
#endif
    };

    UA_UNLOCK(&el->elMutex);
    int selectStatus = UA_select(highestfd+1, &readset, &writeset, &errset, &tmptv);
    UA_LOCK(&el->elMutex);
    if(selectStatus < 0) {
        /* We will retry, only log the error */
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Error during select: %s", errno_str));
        return UA_STATUSCODE_GOOD;
    }

    /* The self-pipe has received. Clear the buffer by reading. */
    if(UA_UNLIKELY(FD_ISSET(el->selfpipe[0], &readset)))
        flushSelfPipe(el->selfpipe[0]);

    /* Loop over all registered FD to see if an event arrived. Yes, this is why
     * select is slow for many open sockets. */
    for(size_t i = 0; i < el->fdsSize; i++) {
        UA_RegisteredFD *rfd = el->fds[i];

        /* The rfd is already registered for removal. Don't process incoming
         * events any longer. */
        if(rfd->dc.callback)
            continue;

        /* Event signaled for the fd? */
        short event = 0;
        if(FD_ISSET(rfd->fd, &readset)) {
            event = UA_FDEVENT_IN;
        } else if(FD_ISSET(rfd->fd, &writeset)) {
            event = UA_FDEVENT_OUT;
        } else if(FD_ISSET(rfd->fd, &errset)) {
            event = UA_FDEVENT_ERR;
        } else {
            continue;
        }

        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Processing event %u on fd %u", (unsigned)event,
                     (unsigned)rfd->fd);

        /* Call the EventSource callback */
        rfd->eventSourceCB(rfd->es, rfd, event);

        /* The fd has removed itself */
        if(i == el->fdsSize || rfd != el->fds[i])
            i--;
    }
    return UA_STATUSCODE_GOOD;
}

#else /* defined(UA_HAVE_EPOLL) */

UA_StatusCode
UA_EventLoopPOSIX_registerFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    struct epoll_event event;
    memset(&event, 0, sizeof(struct epoll_event));
    event.data.ptr = rfd;
    event.events = 0;
    if(rfd->listenEvents & UA_FDEVENT_IN)
        event.events |= EPOLLIN;
    if(rfd->listenEvents & UA_FDEVENT_OUT)
        event.events |= EPOLLOUT;

    int err = epoll_ctl(el->epollfd, EPOLL_CTL_ADD, rfd->fd, &event);
    if(err != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not register for epoll (%s)",
                          rfd->fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_modifyFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    struct epoll_event event;
    memset(&event, 0, sizeof(struct epoll_event));
    event.data.ptr = rfd;
    event.events = 0;
    if(rfd->listenEvents & UA_FDEVENT_IN)
        event.events |= EPOLLIN;
    if(rfd->listenEvents & UA_FDEVENT_OUT)
        event.events |= EPOLLOUT;

    int err = epoll_ctl(el->epollfd, EPOLL_CTL_MOD, rfd->fd, &event);
    if(err != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not modify for epoll (%s)",
                          rfd->fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

void
UA_EventLoopPOSIX_deregisterFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    int res = epoll_ctl(el->epollfd, EPOLL_CTL_DEL, rfd->fd, NULL);
    if(res != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not deregister from epoll (%s)",
                          rfd->fd, errno_str));
    }
}

UA_StatusCode
UA_EventLoopPOSIX_pollFDs(UA_EventLoopPOSIX *el, UA_DateTime listenTimeout) {
    UA_assert(listenTimeout >= 0);

    /* If there is a positive timeout, wait at least one millisecond, the
     * minimum for blocking epoll_wait. This prevents a busy-loop, as the
     * open62541 library allows even smaller timeouts, which can result in a
     * zero timeout due to rounding to an integer here. */
    int timeout = (int)(listenTimeout / UA_DATETIME_MSEC);
    if(timeout == 0 && listenTimeout > 0)
        timeout = 1;

    /* Poll the registered sockets */
    struct epoll_event epoll_events[64];
    UA_UNLOCK(&el->elMutex);
    int events = epoll_wait(el->epollfd, epoll_events, 64, timeout);
    UA_LOCK(&el->elMutex);

    /* TODO: Replace with pwait2 for higher-precision timeouts once this is
     * available in the standard library.
     *
     * struct timespec precisionTimeout = {
     *  (long)(listenTimeout / UA_DATETIME_SEC),
     *   (long)((listenTimeout % UA_DATETIME_SEC) * 100)
     * };
     * int events = epoll_pwait2(epollfd, epoll_events, 64,
     *                        precisionTimeout, NULL); */

    /* Handle error conditions */
    if(events == -1) {
        if(errno == EINTR) {
            /* We will retry, only log the error */
            UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                         "Timeout during poll");
            return UA_STATUSCODE_GOOD;
        }
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP\t| Error %s, closing the server socket",
                          errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Process all received events */
    for(int i = 0; i < events; i++) {
        UA_RegisteredFD *rfd = (UA_RegisteredFD*)epoll_events[i].data.ptr;

        /* The self-pipe has received */
        if(!rfd) {
            flushSelfPipe(el->selfpipe[0]);
            continue;
        }

        /* The rfd is already registered for removal. Don't process incoming
         * events any longer. */
        if(rfd->dc.callback)
            continue;

        /* Get the event */
        short revent = 0;
        if((epoll_events[i].events & EPOLLIN) == EPOLLIN) {
            revent = UA_FDEVENT_IN;
        } else if((epoll_events[i].events & EPOLLOUT) == EPOLLOUT) {
            revent = UA_FDEVENT_OUT;
        } else {
            revent = UA_FDEVENT_ERR;
        }

        /* Call the EventSource callback */
        rfd->eventSourceCB(rfd->es, rfd, revent);
    }
    return UA_STATUSCODE_GOOD;
}

#endif /* defined(UA_HAVE_EPOLL) */

#if defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__)
int UA_EventLoopPOSIX_pipe(SOCKET fds[2]) {
    struct sockaddr_in inaddr;
    memset(&inaddr, 0, sizeof(inaddr));
    inaddr.sin_family = AF_INET;
    inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    inaddr.sin_port = 0;

    SOCKET lst = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    bind(lst, (struct sockaddr *)&inaddr, sizeof(inaddr));
    listen(lst, 1);

    struct sockaddr_storage addr;
    memset(&addr, 0, sizeof(addr));
    int len = sizeof(addr);
    getsockname(lst, (struct sockaddr*)&addr, &len);

    fds[0] = socket(AF_INET, SOCK_STREAM, 0);
    int err = connect(fds[0], (struct sockaddr*)&addr, len);
    fds[1] = accept(lst, 0, 0);
#ifdef UA_ARCHITECTURE_WIN32
    closesocket(lst);
#endif
#ifdef __APPLE__
    close(lst);
#endif

    UA_EventLoopPOSIX_setNoSigPipe(fds[0]);
    UA_EventLoopPOSIX_setReusable(fds[0]);
    UA_EventLoopPOSIX_setNonBlocking(fds[0]);
    UA_EventLoopPOSIX_setNoSigPipe(fds[1]);
    UA_EventLoopPOSIX_setReusable(fds[1]);
    UA_EventLoopPOSIX_setNonBlocking(fds[1]);
    return err;
}
#elif defined(__QNX__)
int UA_EventLoopPOSIX_pipe(int fds[2]) {
    int err = pipe(fds); 
    if(err == -1) {
      return err;
    }

    err = fcntl(fds[0], F_SETFL, O_NONBLOCK);
    if(err == -1) {
      return err;
    }
    return err;
}
#endif

void
UA_EventLoopPOSIX_cancel(UA_EventLoopPOSIX *el) {
    /* Nothing to do if the EventLoop is not executing */
    if(!el->executing)
        return;

    /* Trigger the self-pipe */
#ifdef UA_ARCHITECTURE_WIN32
    int err = send(el->selfpipe[1], ".", 1, 0);
#else
    ssize_t err = write(el->selfpipe[1], ".", 1);
#endif
    if(err <= 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Eventloop\t| Error signaling self-pipe (%s)", errno_str));
    }
}

#endif

/**** amalgamated original file "/arch/posix/eventloop_posix_tcp.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */


#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP) || defined(UA_ARCHITECTURE_WIN32)

/* Configuration parameters */
#define TCP_MANAGERPARAMS 2

static UA_KeyValueRestriction tcpManagerParams[TCP_MANAGERPARAMS] = {
    {{0, UA_STRING_STATIC("recv-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("send-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false}
};

#define TCP_PARAMETERSSIZE 5
#define TCP_PARAMINDEX_ADDR 0
#define TCP_PARAMINDEX_PORT 1
#define TCP_PARAMINDEX_LISTEN 2
#define TCP_PARAMINDEX_VALIDATE 3
#define TCP_PARAMINDEX_REUSE 4

static UA_KeyValueRestriction tcpConnectionParams[TCP_PARAMETERSSIZE] = {
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], false, true, true},
    {{0, UA_STRING_STATIC("port")}, &UA_TYPES[UA_TYPES_UINT16], true, true, false},
    {{0, UA_STRING_STATIC("listen")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("reuse")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false}
};

typedef struct {
    UA_RegisteredFD rfd;

    UA_ConnectionManager_connectionCallback applicationCB;
    void *application;
    void *context;
} TCP_FD;

static void
TCP_shutdown(UA_ConnectionManager *cm, TCP_FD *conn);

static UA_StatusCode
TCP_registerListenSockets(UA_POSIXConnectionManager *pcm, const char *hostname,
                          UA_UInt16 port, void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate, UA_Boolean reuseaddr);

/* Do not merge packets on the socket (disable Nagle's algorithm) */
static UA_StatusCode
TCP_setNoNagle(UA_FD sockfd) {
    int val = 1;
    int res = UA_setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
    if(res < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

/* Test if the ConnectionManager can be stopped */
static void
TCP_checkStopped(UA_POSIXConnectionManager *pcm) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);

    if(pcm->fdsSize == 0 &&
       pcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING) {
        UA_LOG_DEBUG(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| All sockets closed, the EventLoop has stopped");
        pcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
    }
}

static void
TCP_delayedReopen(void *application, void *context) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_ConnectionManager *cm = &pcm->cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_DeregisteredListenFD *listenRfd = (UA_DeregisteredListenFD*)context;
    UA_RegisteredFD *rfd = listenRfd->listenFd;
    TCP_FD *conn = (TCP_FD*)rfd;

    UA_LOCK(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "TCP %u\t| Delayed reopen of the listen socket",
                 (unsigned)conn->rfd.fd);

    char hostname[UA_MAXHOSTNAME_LENGTH] = {0};
    mp_snprintf(hostname, UA_MAXHOSTNAME_LENGTH, "%.*s",
                (int)rfd->hostname.length, (char*)rfd->hostname.data);

    TCP_registerListenSockets(pcm, hostname, rfd->port, conn->application,
                              conn->context, conn->applicationCB, false, rfd->reuseaddr);

    LIST_REMOVE(listenRfd, pointers);
    UA_String_clear(&listenRfd->listenFd->hostname);
    UA_free(listenRfd->listenFd);
    UA_free(listenRfd);

    if(!pcm->listenFDs.lh_first) {
        el->maxSocketsLimitReached = false;
    }

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
addListenSockets(void *application) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    UA_DeregisteredListenFD *listenFd;
    LIST_FOREACH(listenFd, &pcm->listenFDs, pointers) {
        if(listenFd->listenFd->dc.callback) {
            UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "TCP %u\t| Cannot close - already closing",
                         (unsigned)listenFd->listenFd->fd);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
             "TCP %u\t| Reopen listen socket triggered",
             (unsigned)listenFd->listenFd->fd);

        /* Add to the delayed callback list. Will be cleaned up in the next
         * iteration. */
        UA_DelayedCallback *dc = &listenFd->listenFd->dc;
        dc->callback = TCP_delayedReopen;
        dc->application = application;
        dc->context = listenFd;

        /* Adding a delayed callback does not take a lock */
        UA_EventLoopPOSIX_addDelayedCallback(pcm->cm.eventSource.eventLoop, dc);
    }
    return UA_STATUSCODE_GOOD;
}

static void
TCP_delayedClose(void *application, void *context) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_ConnectionManager *cm = &pcm->cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    TCP_FD *conn = (TCP_FD*)context;

    UA_LOCK(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "TCP %u\t| Delayed closing of the connection",
                 (unsigned)conn->rfd.fd);

    /* Ensure reuse is possible right away. Port-stealing is no longer an issue
     * as the socket gets closed anyway. And we do not want to wait for the
     * timeout to open a new socket for the same address and port. */
    UA_EventLoopPOSIX_setReusable(conn->rfd.fd);

    /* Deregister from the EventLoop */
    UA_EventLoopPOSIX_deregisterFD(el, &conn->rfd);

    /* Deregister internally */
    ZIP_REMOVE(UA_FDTree, &pcm->fds, &conn->rfd);
    UA_assert(pcm->fdsSize > 0);
    pcm->fdsSize--;

    /* Signal closing to the application */
    conn->applicationCB(cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_CLOSING,
                        &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);

    /* Close the socket */
    UA_RESET_ERRNO;
    int ret = UA_close(conn->rfd.fd);
    if(ret == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| Socket closed", (unsigned)conn->rfd.fd);
    } else {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not close the socket (%s)",
                          (unsigned)conn->rfd.fd, errno_str));
    }

    /* Resuming listen sockets in the socket list when socket space becomes available */
    if(el->maxSocketsLimitReached) {
        addListenSockets(application);
    }

    UA_String_clear(&conn->rfd.hostname);
    UA_free(conn);

    /* Check if this was the last connection for a closing ConnectionManager */
    TCP_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static int
getSockError(TCP_FD *conn) {
    int error = 0;
#ifndef UA_ARCHITECTURE_WIN32
    socklen_t errlen = sizeof(int);
    int err = UA_getsockopt(conn->rfd.fd, SOL_SOCKET, SO_ERROR, &error, &errlen);
#else
    int errlen = (int)sizeof(int);
    int err = UA_getsockopt((SOCKET)conn->rfd.fd, SOL_SOCKET, SO_ERROR,
                         (char*)&error, &errlen);
#endif
    return (err == 0) ? error : err;
}

/* Gets called when a connection socket opens, receives data or closes */
static void
TCP_connectionSocketCallback(UA_ConnectionManager *cm, TCP_FD *conn,
                             short event) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Activity on the socket",
                 (unsigned)conn->rfd.fd);

    /* Error. The connection has closed. */
    if(event == UA_FDEVENT_ERR) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| The connection closes with error %i",
                    (unsigned)conn->rfd.fd, getSockError(conn));
        TCP_shutdown(cm, conn);
        return;
    }

    /* Write-Event, a new connection has opened. But some errors come as an
     * out-event. For example if the remote side could not be reached to
     * initiate the connection. So we check manually for error conditions on
     * the socket. */
    if(event == UA_FDEVENT_OUT) {
        int error = getSockError(conn);
        if(error != 0) {
            UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "TCP %u\t| The connection closes with error %i",
                        (unsigned)conn->rfd.fd, error);
            TCP_shutdown(cm, conn);
            return;
        }

        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP %u\t| Opening a new connection",
                     (unsigned)conn->rfd.fd);

        /* Now we are interested in read-events. */
        conn->rfd.listenEvents = UA_FDEVENT_IN;
        UA_EventLoopPOSIX_modifyFD(el, &conn->rfd);

        /* A new socket has opened. Signal it to the application. */
        conn->applicationCB(cm, (uintptr_t)conn->rfd.fd,
                            conn->application, &conn->context,
                            UA_CONNECTIONSTATE_ESTABLISHED,
                            &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Allocate receive buffer",
                 (unsigned)conn->rfd.fd);

    /* Use the already allocated receive-buffer */
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_ByteString response = pcm->rxBuffer;

    /* Receive */
    UA_RESET_ERRNO;
#ifndef UA_ARCHITECTURE_WIN32
    ssize_t ret = UA_recv(conn->rfd.fd, (char*)response.data,
                          response.length, MSG_DONTWAIT);
#else
    int ret = UA_recv(conn->rfd.fd, (char*)response.data,
                      response.length, MSG_DONTWAIT);
#endif

    /* Receive has failed */
    if(ret <= 0) {
        if(ret < 0 && (UA_ERRNO == UA_INTERRUPTED ||
                        UA_ERRNO == UA_WOULDBLOCK ||
                        UA_ERRNO == UA_AGAIN))
            return; /* Temporary error on an non-blocking socket */

        /* Orderly shutdown of the socket */
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "TCP %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)conn->rfd.fd, errno_str));
        TCP_shutdown(cm, conn);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Received message of size %u",
                 (unsigned)conn->rfd.fd, (unsigned)ret);

    /* Callback to the application layer */
    response.length = (size_t)ret; /* Set the length of the received buffer */
    conn->applicationCB(cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_ESTABLISHED,
                        &UA_KEYVALUEMAP_NULL, response);
}

static void *
removeListenSockets(void *application, UA_RegisteredFD *rfd) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    int optval;
    socklen_t optlen = sizeof(optval);

    if(UA_getsockopt(rfd->fd, SOL_SOCKET, SO_ACCEPTCONN, &optval, &optlen) == 0 && optval) {
        TCP_FD *fd = (TCP_FD*)rfd;
        /* Check if it's already listed for reopening */
        UA_Boolean alreadyAdded = UA_FALSE;
        UA_DeregisteredListenFD *listenFd;
        LIST_FOREACH(listenFd, &pcm->listenFDs, pointers) {
            if(UA_String_equal(&listenFd->listenFd->hostname, &rfd->hostname)){
                alreadyAdded = UA_TRUE;
                break;
            }
        }

        if(!alreadyAdded) {
            listenFd = (UA_DeregisteredListenFD*)UA_calloc(1, sizeof(UA_DeregisteredListenFD));
            listenFd->listenFd = rfd;
            LIST_INSERT_HEAD(&pcm->listenFDs, listenFd, pointers);
        }

        /* Ensure reuse is possible right away. Port-stealing is no longer an issue
         * as the socket gets closed anyway. And we do not want to wait for the
         * timeout to open a new socket for the same address and port. */
        UA_EventLoopPOSIX_setReusable(rfd->fd);
        UA_EventLoopPOSIX_deregisterFD(el, rfd);

        /* Deregister internally */
        ZIP_REMOVE(UA_FDTree, &pcm->fds, rfd);
        UA_assert(pcm->fdsSize > 0);
        pcm->fdsSize--;

        /* Signal closing to the application */
        fd->applicationCB(&pcm->cm, (uintptr_t)rfd->fd,
                          fd->application, &fd->context,
                          UA_CONNECTIONSTATE_BLOCKING,
                          &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);

        /* Close the socket */
        UA_RESET_ERRNO;
        int ret = UA_close(rfd->fd);
        if(ret == 0) {
            UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "TCP %u\t| Socket closed", (unsigned)rfd->fd);
        } else {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                              "TCP %u\t| Could not close the socket (%s)",
                              (unsigned)rfd->fd, errno_str));
        }

        if(alreadyAdded) {
            UA_String_clear(&rfd->hostname);
            UA_free(rfd);
        }
    }

    return NULL;
}

/* Gets called when a new connection opens or if the listenSocket is closed */
static void
TCP_listenSocketCallback(UA_ConnectionManager *cm, TCP_FD *conn, short event) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Callback on server socket",
                 (unsigned)conn->rfd.fd);

    /* Try to accept a new connection */
    UA_RESET_ERRNO;
    struct sockaddr_storage remote;
    socklen_t remote_size = sizeof(remote);
    UA_FD newsockfd = UA_accept(conn->rfd.fd, (struct sockaddr*)&remote, &remote_size);
    if(newsockfd == UA_INVALID_FD) {
        /* Temporary error -- retry */
        if(UA_IS_TEMPORARY_ACCEPT_ERROR(UA_ERRNO))
            return;

        /* Close the listen socket */
        if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPING) {
            UA_LOG_SOCKET_ERRNO_WRAP(
                UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                               "TCP %u\t| Error %s, closing the server socket",
                               (unsigned)conn->rfd.fd, errno_str));
        }

        TCP_shutdown(cm, conn);
        return;
    }

    /* Log the name of the remote host */
    UA_RESET_ERRNO;
    char hoststr[UA_MAXHOSTNAME_LENGTH];
    int get_res = UA_getnameinfo((struct sockaddr *)&remote, sizeof(remote),
                                 hoststr, sizeof(hoststr),
                                 NULL, 0, NI_NUMERICHOST);
    if(get_res != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| getnameinfo(...) could not resolve the "
                          "hostname (%s)", (unsigned)conn->rfd.fd, errno_str));
    }
    UA_LOG_INFO(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                "TCP %u\t| Connection opened from \"%s\" via the server socket %u",
                (unsigned)newsockfd, hoststr, (unsigned)conn->rfd.fd);

    /* Configure the new socket */
    UA_RESET_ERRNO;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    /* res |= UA_EventLoopPOSIX_setNonBlocking(newsockfd); Inherited from the listen-socket */
    res |= UA_EventLoopPOSIX_setNoSigPipe(newsockfd); /* Supress interrupts from the socket */
    res |= TCP_setNoNagle(newsockfd);     /* Disable Nagle's algorithm */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                           "TCP %u\t| Error seeting the TCP options (%s)",
                           (unsigned)newsockfd, errno_str));
        /* Close the new socket */
        UA_close(newsockfd);
        return;
    }

    /* Allocate the UA_RegisteredFD */
    TCP_FD *newConn = (TCP_FD*)UA_calloc(1, sizeof(TCP_FD));
    if(!newConn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error allocating memory for the socket",
                       (unsigned)newsockfd);
        UA_close(newsockfd);
        return;
    }

    newConn->rfd.fd = newsockfd;
    newConn->rfd.listenEvents = UA_FDEVENT_IN;
    newConn->rfd.es = &cm->eventSource;
    newConn->rfd.eventSourceCB = (UA_FDCallback)TCP_connectionSocketCallback;
    newConn->applicationCB = conn->applicationCB;
    newConn->application = conn->application;
    newConn->context = conn->context;

    /* Register in the EventLoop. Signal to the user if registering failed. */
    res = UA_EventLoopPOSIX_registerFD(el, &newConn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error registering the socket",
                       (unsigned)newsockfd);
        UA_free(newConn);
        UA_close(newsockfd);
        return;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newConn->rfd);
    pcm->fdsSize++;

    /* Verify whether the maximum socket limit has been exceeded.
     * If true, remove listen sockets from the socket list to stop
     * accepting additional connection requests */
    const UA_UInt32 *maxSockets = (const UA_UInt32 *)UA_KeyValueMap_getScalar(
        &cm->eventSource.params, UA_QUALIFIEDNAME(0, "max-connections"),
        &UA_TYPES[UA_TYPES_UINT32]);
    if(maxSockets && *maxSockets != 0 && pcm->fdsSize >= (size_t)*maxSockets) {
        ZIP_ITER(UA_FDTree, &pcm->fds, removeListenSockets, cm);
        el->maxSocketsLimitReached = true;
    }

    /* Forward the remote hostname to the application */
    UA_KeyValuePair kvp;
    kvp.key = UA_QUALIFIEDNAME(0, "remote-address");
    UA_String hostName = UA_STRING(hoststr);
    UA_Variant_setScalar(&kvp.value, &hostName, &UA_TYPES[UA_TYPES_STRING]);

    UA_KeyValueMap kvm;
    kvm.mapSize = 1;
    kvm.map = &kvp;

    /* The socket has opened. Signal it to the application. */
    newConn->applicationCB(cm, (uintptr_t)newsockfd,
                           newConn->application, &newConn->context,
                           UA_CONNECTIONSTATE_ESTABLISHED,
                           &kvm, UA_BYTESTRING_NULL);
}

static UA_StatusCode
TCP_registerListenSocket(UA_POSIXConnectionManager *pcm, struct addrinfo *ai,
                         const char *hostname, UA_UInt16 port,
                         void *application, void *context,
                         UA_ConnectionManager_connectionCallback connectionCallback,
                         UA_Boolean validate, UA_Boolean reuseaddr) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Check that the maximum number of sockets has not been exceeded */
    const UA_UInt32 *maxSockets = (const UA_UInt32 *)UA_KeyValueMap_getScalar(
        &pcm->cm.eventSource.params, UA_QUALIFIEDNAME(0, "max-connections"),
        &UA_TYPES[UA_TYPES_UINT32]);
    if(el->maxSocketsLimitReached || (maxSockets && *maxSockets != 0 && pcm->fdsSize >= (size_t)*maxSockets)) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| Unable to establish connection: no available sockets");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Translate INADDR_ANY to IPv4/IPv6 address */
    UA_RESET_ERRNO;
    char addrstr[UA_MAXHOSTNAME_LENGTH];
    int get_res = UA_getnameinfo(ai->ai_addr, ai->ai_addrlen,
                                 addrstr, sizeof(addrstr), NULL, 0, 0);
    if(get_res != 0) {
        get_res = UA_getnameinfo(ai->ai_addr, ai->ai_addrlen,
                                 addrstr, sizeof(addrstr),
                                 NULL, 0, NI_NUMERICHOST);
        if(get_res != 0) {
            addrstr[0] = 0;
            UA_LOG_SOCKET_ERRNO_WRAP(
                UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                               "TCP\t| getnameinfo(...) could not resolve the "
                               "hostname (%s)", errno_str));
        }
    }

    /* Create the server socket */
    UA_RESET_ERRNO;
    UA_FD listenSocket = UA_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if(listenSocket == UA_INVALID_FD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Error opening the listen socket for "
                          "\"%s\" on port %u (%s)",
                          (unsigned)listenSocket, addrstr, port, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Some Linux distributions have net.ipv6.bindv6only not activated. So
     * sockets can double-bind to IPv4 and IPv6. This leads to problems. Use
     * AF_INET6 sockets only for IPv6. */
#if UA_IPV6
    int optval = 1;
    if(ai->ai_family == AF_INET6 &&
       UA_setsockopt(listenSocket, IPPROTO_IPV6, IPV6_V6ONLY,
                     (const char*)&optval, sizeof(optval)) == -1) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not set an IPv6 socket to IPv6 only",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
#endif

    /* Allow rebinding to the IP/port combination. Eg. to restart the server. */
    if(reuseaddr &&
       UA_EventLoopPOSIX_setReusable(listenSocket) != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not make the socket addr reusable",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Set the socket non-blocking */
    if(UA_EventLoopPOSIX_setNonBlocking(listenSocket) != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not set the socket non-blocking",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Supress interrupts from the socket */
    if(UA_EventLoopPOSIX_setNoSigPipe(listenSocket) != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not disable SIGPIPE",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Bind socket to address */
    UA_RESET_ERRNO;
    int ret = UA_bind(listenSocket, ai->ai_addr, (socklen_t)ai->ai_addrlen);

    /* Get the port being used if dynamic porting was used */
    if(port == 0) {
        struct sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        socklen_t len = sizeof(sin);
        UA_getsockname(listenSocket, (struct sockaddr *)&sin, &len);
        port = ntohs(sin.sin_port);
    }

    /* If the INADDR_ANY is used, use the local hostname */
    char hoststr[UA_MAXHOSTNAME_LENGTH];
    if(hostname) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| Creating listen socket for \"%s\" on port %u",
                    (unsigned)listenSocket, hostname, port);
    } else {
        UA_gethostname(hoststr, UA_MAXHOSTNAME_LENGTH);
        hostname = hoststr;
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| Creating listen socket for \"%s\" "
                    "(with local hostname \"%s\") on port %u",
                    (unsigned)listenSocket, addrstr, hostname, port);
    }

    if(ret < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Error binding the socket to the address %s (%s)",
                          (unsigned)listenSocket, hostname, errno_str));
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Only validate, don't actually start listening */
    if(validate) {
        UA_EventLoopPOSIX_setReusable(listenSocket); /* Ensure reuse is possible */
        UA_close(listenSocket);
        return UA_STATUSCODE_GOOD;
    }

    /* Start listening */
    UA_RESET_ERRNO;
    if(UA_listen(listenSocket, UA_MAXBACKLOG) < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Error listening on the socket (%s)",
                          (unsigned)listenSocket, errno_str));
        UA_EventLoopPOSIX_setReusable(listenSocket); /* Ensure reuse is possible */
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Allocate the connection */
    TCP_FD *newConn = (TCP_FD*)UA_calloc(1, sizeof(TCP_FD));
    if(!newConn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error allocating memory for the socket",
                       (unsigned)listenSocket);
        UA_EventLoopPOSIX_setReusable(listenSocket); /* Ensure reuse is possible */
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    newConn->rfd.fd = listenSocket;
    newConn->rfd.listenEvents = UA_FDEVENT_IN;
    newConn->rfd.es = &pcm->cm.eventSource;
    newConn->rfd.eventSourceCB = (UA_FDCallback)TCP_listenSocketCallback;
    newConn->applicationCB = connectionCallback;
    newConn->application = application;
    newConn->context = context;

    /* Information to reopen listen socket */
    newConn->rfd.hostname = UA_String_fromChars(hostname);
    newConn->rfd.port = port;
    newConn->rfd.reuseaddr = reuseaddr;

    /* Register in the EventLoop */
    UA_StatusCode res = UA_EventLoopPOSIX_registerFD(el, &newConn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error registering the socket",
                       (unsigned)listenSocket);
        UA_free(newConn);
        UA_EventLoopPOSIX_setReusable(listenSocket); /* Ensure reuse is possible */
        UA_close(listenSocket);
        return res;
    }

    /* Register internally */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newConn->rfd);
    pcm->fdsSize++;

    /* Set up the callback parameters */
    UA_String listenAddress = UA_STRING((char*)(uintptr_t)hostname);
    UA_KeyValuePair params[2];
    params[0].key = UA_QUALIFIEDNAME(0, "listen-address");
    UA_Variant_setScalar(&params[0].value, &listenAddress, &UA_TYPES[UA_TYPES_STRING]);
    params[1].key = UA_QUALIFIEDNAME(0, "listen-port");
    UA_Variant_setScalar(&params[1].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    UA_KeyValueMap paramMap = {2, params};

    if(el->maxSocketsLimitReached) {
        /* Announce the reopening of the listen-socket in the application */
        connectionCallback(&pcm->cm, (uintptr_t)listenSocket,
                           application, &newConn->context,
                           UA_CONNECTIONSTATE_REOPENING,
                           &paramMap, UA_BYTESTRING_NULL);
        return UA_STATUSCODE_GOOD;
    }

    /* Announce the listen-socket in the application */
    connectionCallback(&pcm->cm, (uintptr_t)listenSocket,
                       application, &newConn->context,
                       UA_CONNECTIONSTATE_ESTABLISHED,
                       &paramMap, UA_BYTESTRING_NULL);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
TCP_registerListenSockets(UA_POSIXConnectionManager *pcm, const char *hostname,
                          UA_UInt16 port, void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate, UA_Boolean reuseaddr) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);

    /* Create a string for the port */
    char portstr[6];
    mp_snprintf(portstr, sizeof(portstr), "%d", port);

    /* Get all the interface and IPv4/6 combinations for the configured hostname */
    struct addrinfo hints, *res;
    memset(&hints, 0, sizeof hints);
#if UA_IPV6
    hints.ai_family = AF_UNSPEC; /* Allow IPv4 and IPv6 */
#else
    hints.ai_family = AF_INET;   /* IPv4 only */
#endif
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    UA_RESET_ERRNO;
    int retcode = UA_getaddrinfo(hostname, portstr, &hints, &res);
    if(retcode != 0) {
       UA_LOG_SOCKET_ERRNO_GAI_WRAP(
       UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                      "TCP\t| Lookup for \"%s\" on port %u failed (%s)",
                      hostname, port, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Add listen sockets. Aggregate the results to see if at least one
     * listen-socket was established. */
    UA_StatusCode total_result = UA_INT32_MAX;
    struct addrinfo *ai = res;
    while(ai) {
        total_result &= TCP_registerListenSocket(pcm, ai, hostname, port, application, context,
                                                 connectionCallback, validate, reuseaddr);
        ai = ai->ai_next;
    }
    UA_freeaddrinfo(res);

    return total_result;
}

/* Close the connection via a delayed callback */
static void
TCP_shutdown(UA_ConnectionManager *cm, TCP_FD *conn) {
    /* Already closing - nothing to do */
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    if(conn->rfd.dc.callback) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP %u\t| Cannot close - already closing",
                     (unsigned)conn->rfd.fd);
        return;
    }

    /* Shutdown the socket to cancel the current select/epoll */
    UA_shutdown(conn->rfd.fd, UA_SHUT_RDWR);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Shutdown triggered",
                 (unsigned)conn->rfd.fd);

    /* Add to the delayed callback list. Will be cleaned up in the next
     * iteration. */
    UA_DelayedCallback *dc = &conn->rfd.dc;
    dc->callback = TCP_delayedClose;
    dc->application = cm;
    dc->context = conn;

    /* Adding a delayed callback does not take a lock */
    UA_EventLoopPOSIX_addDelayedCallback((UA_EventLoop*)el, dc);
}

static UA_StatusCode
TCP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    UA_FD fd = (UA_FD)connectionId;
    TCP_FD *conn = (TCP_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!conn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Cannot close TCP connection %u - not found",
                       (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    TCP_shutdown(cm, conn);

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
TCP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
                       const UA_KeyValueMap *params, UA_ByteString *buf) {
    /* We may not have a lock. But we need not take it. As the connectionId is
     * the fd, no need to do a lookup and access internal data strucures. */

    /* Prevent OS signals when sending to a closed socket */
    int flags = MSG_NOSIGNAL;

    struct pollfd tmp_poll_fd;
    tmp_poll_fd.fd = (UA_FD)connectionId;
    tmp_poll_fd.events = UA_POLLOUT;

    /* Send the full buffer. This may require several calls to send */
    size_t nWritten = 0;
    do {
        ssize_t n = 0;
        do {
            UA_RESET_ERRNO;
            UA_LOG_DEBUG(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                         "TCP %u\t| Attempting to send", (unsigned)connectionId);
            size_t bytes_to_send = buf->length - nWritten;
            n = UA_send((UA_FD)connectionId,
                        (const char*)buf->data + nWritten,
                        bytes_to_send, flags);
            if(n < 0) {
                /* An error we cannot recover from? */
                if(UA_ERRNO != UA_INTERRUPTED && UA_ERRNO != UA_WOULDBLOCK &&
                   UA_ERRNO != UA_AGAIN)
                    goto shutdown;

                /* Poll for the socket resources to become available and retry
                 * (blocking) */
                int poll_ret;
                do {
                    UA_RESET_ERRNO;
                    poll_ret = UA_poll(&tmp_poll_fd, 1, 100);
                    if(poll_ret < 0 && UA_ERRNO != UA_INTERRUPTED)
                        goto shutdown;
                } while(poll_ret <= 0);
            }
        } while(n < 0);
        nWritten += (size_t)n;
    } while(nWritten < buf->length);

    /* Clean up and return */
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_GOOD;

 shutdown:
    /* Error -> shutdown the connection  */
    UA_LOG_SOCKET_ERRNO_WRAP(
       UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| Send failed with error %s",
                    (unsigned)connectionId, errno_str));
    TCP_shutdownConnection(cm, connectionId);
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_BADCONNECTIONCLOSED;
}

/* Create a listen-socket that waits for incoming connections */
static UA_StatusCode
TCP_openPassiveConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                          void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Get the port parameter */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, tcpConnectionParams[TCP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* existence is checked before */

    /* Get the address parameter */
    const UA_Variant *addrs =
        UA_KeyValueMap_get(params, tcpConnectionParams[TCP_PARAMINDEX_ADDR].name);
    size_t addrsSize = 0;
    if(addrs) {
        UA_assert(addrs->type == &UA_TYPES[UA_TYPES_STRING]);
        if(UA_Variant_isScalar(addrs))
            addrsSize = 1;
        else
            addrsSize = addrs->arrayLength;
    }

    /* Get the reuseaddr parameter */
    UA_Boolean reuseaddr = false;
    const UA_Boolean *reuseaddrTmp = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, tcpConnectionParams[TCP_PARAMINDEX_REUSE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(reuseaddrTmp)
        reuseaddr = *reuseaddrTmp;

    /* Undefined or empty addresses array -> listen on all interfaces */
    UA_StatusCode retval = UA_STATUSCODE_BADINTERNALERROR;
    if(addrsSize == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP\t| Listening on all interfaces");
        if(TCP_registerListenSockets(pcm, NULL, *port, application,
                                     context, connectionCallback, validate, reuseaddr) == UA_STATUSCODE_GOOD)
            retval = UA_STATUSCODE_GOOD;
        return retval;
    }

    /* Iterate over the configured hostnames */
    UA_String *hostStrings = (UA_String*)addrs->data;
    for(size_t i = 0; i < addrsSize; i++) {
        char hostname[512];
        if(hostStrings[i].length >= sizeof(hostname))
            continue;
        memcpy(hostname, hostStrings[i].data, hostStrings->length);
        hostname[hostStrings->length] = '\0';
        if(TCP_registerListenSockets(pcm, hostname, *port, application,
                                     context, connectionCallback, validate, reuseaddr) == UA_STATUSCODE_GOOD)
            retval = UA_STATUSCODE_GOOD;
    }
    return retval;
}

/* Open a TCP connection to a remote host */
static UA_StatusCode
TCP_openActiveConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                         void *application, void *context,
                         UA_ConnectionManager_connectionCallback connectionCallback,
                         UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Check that the maximum number of sockets has not been exceeded */
    const UA_UInt32 *maxSockets = (const UA_UInt32 *)UA_KeyValueMap_getScalar(
        &pcm->cm.eventSource.params, UA_QUALIFIEDNAME(0, "max-connections"),
        &UA_TYPES[UA_TYPES_UINT32]);
    if(el->maxSocketsLimitReached || (maxSockets && *maxSockets != 0 && pcm->fdsSize >= (size_t)*maxSockets)) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| Unable to establish connection: no available sockets");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Get the connection parameters */
    char hostname[UA_MAXHOSTNAME_LENGTH];
    char portStr[UA_MAXPORTSTR_LENGTH];

    /* Prepare the port parameter as a string */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, tcpConnectionParams[TCP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* existence is checked before */
    mp_snprintf(portStr, UA_MAXPORTSTR_LENGTH, "%d", *port);

    /* Prepare the hostname string */
    const UA_String *addr = (const UA_String*)
        UA_KeyValueMap_getScalar(params, tcpConnectionParams[TCP_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(!addr) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| Open TCP Connection: No hostname defined, aborting");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(addr->length >= UA_MAXHOSTNAME_LENGTH) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "TCP\t| Open TCP Connection: Hostname too long, aborting");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    strncpy(hostname, (const char*)addr->data, addr->length);
    hostname[addr->length] = 0;

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP\t| Open a connection to \"%s\" on port %s", hostname, portStr);

    /* Create the socket description from the connectString
     * TODO: Make this non-blocking */
    UA_RESET_ERRNO;
    struct addrinfo hints, *info;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    int error = UA_getaddrinfo(hostname, portStr, &hints, &info);
    if(error != 0) {
       UA_LOG_SOCKET_ERRNO_GAI_WRAP(
       UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                      "TCP\t| Lookup of %s failed (%s)",
                      hostname, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create a socket */
    UA_RESET_ERRNO;
    UA_FD newSock = UA_socket(info->ai_family, info->ai_socktype, info->ai_protocol);
    if(newSock == UA_INVALID_FD) {
        UA_freeaddrinfo(info);
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                           "TCP\t| Could not create socket to connect to %s (%s)",
                           hostname, errno_str));
        return UA_STATUSCODE_BADDISCONNECT;
    }

    /* Set the socket options */
    UA_RESET_ERRNO;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_EventLoopPOSIX_setNonBlocking(newSock);
    res |= UA_EventLoopPOSIX_setNoSigPipe(newSock);
    res |= TCP_setNoNagle(newSock);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                           "TCP\t| Could not set socket options: %s", errno_str));
        UA_freeaddrinfo(info);
        UA_close(newSock);
        return res;
    }

    /* Only validate, don't actually open the connection */
    if(validate) {
        UA_freeaddrinfo(info);
        UA_close(newSock);
        return UA_STATUSCODE_GOOD;
    }

    /* Non-blocking connect */
    UA_RESET_ERRNO;
    error = UA_connect(newSock, info->ai_addr, info->ai_addrlen);
    UA_freeaddrinfo(info);
    if(error != 0 &&
       UA_ERRNO != UA_INPROGRESS &&
       UA_ERRNO != UA_WOULDBLOCK) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                           "TCP\t| Connecting the socket to %s failed (%s)",
                           hostname, errno_str));
        UA_close(newSock);
        return UA_STATUSCODE_BADDISCONNECT;
    }

    /* Allocate the UA_RegisteredFD */
    TCP_FD *newConn = (TCP_FD*)UA_calloc(1, sizeof(TCP_FD));
    if(!newConn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error allocating memory for the socket",
                       (unsigned)newSock);
        UA_close(newSock);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    newConn->rfd.fd = newSock;
    newConn->rfd.es = &pcm->cm.eventSource;
    newConn->rfd.eventSourceCB = (UA_FDCallback)TCP_connectionSocketCallback;
    newConn->rfd.listenEvents = UA_FDEVENT_OUT; /* Switched to _IN once the
                                                 * connection is open */
    newConn->applicationCB = connectionCallback;
    newConn->application = application;
    newConn->context = context;

    /* Register the fd to trigger when output is possible (the connection is open) */
    res = UA_EventLoopPOSIX_registerFD(el, &newConn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Registering the socket to connect to %s failed", hostname);
        UA_close(newSock);
        UA_free(newConn);
        return res;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newConn->rfd);
    pcm->fdsSize++;

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "TCP %u\t| Opening a connection to \"%s\" on port %s",
                (unsigned)newSock, hostname, portStr);

    /* Signal the new connection to the application as asynchonously opening */
    connectionCallback(&pcm->cm, (uintptr_t)newSock,
                       application, &newConn->context,
                       UA_CONNECTIONSTATE_OPENING, &UA_KEYVALUEMAP_NULL,
                       UA_BYTESTRING_NULL);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
TCP_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
                   void *application, void *context,
                   UA_ConnectionManager_connectionCallback connectionCallback) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STARTED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| Cannot open a connection for a "
                     "ConnectionManager that is not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "TCP",
                                        tcpConnectionParams,
                                        TCP_PARAMETERSSIZE, params);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&el->elMutex);
        return res;
    }

    /* Only validate the parameters? */
    UA_Boolean validate = false;
    const UA_Boolean *validateParam = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 tcpConnectionParams[TCP_PARAMINDEX_VALIDATE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(validateParam)
        validate = *validateParam;

    /* Listen or active connection? */
    UA_Boolean listen = false;
    const UA_Boolean *listenParam = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 tcpConnectionParams[TCP_PARAMINDEX_LISTEN].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(listenParam)
        listen = *listenParam;

    if(listen) {
        res = TCP_openPassiveConnection(pcm, params, application, context,
                                        connectionCallback, validate);
    } else {
        res = TCP_openActiveConnection(pcm, params, application, context,
                                       connectionCallback, validate);
    }

    UA_UNLOCK(&el->elMutex);
    return res;
}

static UA_StatusCode
TCP_eventSourceStart(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| To start the ConnectionManager, it has to be "
                     "registered in an EventLoop and not started yet");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "TCP",
                                        tcpManagerParams, TCP_MANAGERPARAMS,
                                        &cm->eventSource.params);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Allocate the rx buffer */
    res = UA_EventLoopPOSIX_allocateStaticBuffers(pcm);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Set the EventSource to the started state */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;

 finish:
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void *
TCP_shutdownCB(void *application, UA_RegisteredFD *rfd) {
    UA_ConnectionManager *cm = (UA_ConnectionManager*)application;
    TCP_shutdown(cm, (TCP_FD*)rfd);
    return NULL;
}

static void
TCP_eventSourceStop(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    (void)el;

    UA_LOCK(&el->elMutex);

    UA_LOG_DEBUG(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                 "TCP\t| Shutting down the ConnectionManager");

    /* Prevent new connections to open */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;

    /* Shutdown all existing connection */
    ZIP_ITER(UA_FDTree, &pcm->fds, TCP_shutdownCB, cm);

    /* All sockets closed? Otherwise iterate some more. */
    TCP_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
TCP_eventSourceDelete(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(cm->eventSource.state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "TCP\t| The EventSource must be stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_ByteString_clear(&pcm->rxBuffer);
    UA_ByteString_clear(&pcm->txBuffer);
    UA_KeyValueMap_clear(&cm->eventSource.params);
    UA_String_clear(&cm->eventSource.name);
    UA_free(cm);

    return UA_STATUSCODE_GOOD;
}

static const char *tcpName = "tcp";

UA_ConnectionManager *
UA_ConnectionManager_new_POSIX_TCP(const UA_String eventSourceName) {
    UA_POSIXConnectionManager *cm = (UA_POSIXConnectionManager*)
        UA_calloc(1, sizeof(UA_POSIXConnectionManager));
    if(!cm)
        return NULL;

    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))TCP_eventSourceStart;
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))TCP_eventSourceStop;
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))TCP_eventSourceDelete;
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)tcpName);
    cm->cm.openConnection = TCP_openConnection;
    cm->cm.allocNetworkBuffer = UA_EventLoopPOSIX_allocNetworkBuffer;
    cm->cm.freeNetworkBuffer = UA_EventLoopPOSIX_freeNetworkBuffer;
    cm->cm.sendWithConnection = TCP_sendWithConnection;
    cm->cm.closeConnection = TCP_shutdownConnection;
    return &cm->cm;
}

#endif

/**** amalgamated original file "/arch/posix/eventloop_posix_udp.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */


#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP) || defined(UA_ARCHITECTURE_WIN32)

#define IPV4_PREFIX_MASK 0xF0
#define IPV4_MULTICAST_PREFIX 0xE0
#if UA_IPV6
# define IPV6_PREFIX_MASK 0xFF
# define IPV6_MULTICAST_PREFIX 0xFF
#endif

/* Configuration parameters */

#define UDP_MANAGERPARAMS 2

static UA_KeyValueRestriction udpManagerParams[UDP_MANAGERPARAMS] = {
    {{0, UA_STRING_STATIC("recv-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("send-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false}
};

#define UDP_PARAMETERSSIZE 9
#define UDP_PARAMINDEX_LISTEN 0
#define UDP_PARAMINDEX_ADDR 1
#define UDP_PARAMINDEX_PORT 2
#define UDP_PARAMINDEX_INTERFACE 3
#define UDP_PARAMINDEX_TTL 4
#define UDP_PARAMINDEX_LOOPBACK 5
#define UDP_PARAMINDEX_REUSE 6
#define UDP_PARAMINDEX_SOCKPRIO 7
#define UDP_PARAMINDEX_VALIDATE 8

static UA_KeyValueRestriction udpConnectionParams[UDP_PARAMETERSSIZE] = {
    {{0, UA_STRING_STATIC("listen")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], false, true, true},
    {{0, UA_STRING_STATIC("port")}, &UA_TYPES[UA_TYPES_UINT16], true, true, false},
    {{0, UA_STRING_STATIC("interface")}, &UA_TYPES[UA_TYPES_STRING], false, true, false},
    {{0, UA_STRING_STATIC("ttl")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("loopback")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("reuse")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("sockpriority")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false}
};

/* A registered file descriptor with an additional method pointer */
typedef struct {
    UA_RegisteredFD rfd;

    UA_ConnectionManager_connectionCallback applicationCB;
    void *application;
    void *context;

    struct sockaddr_storage sendAddr;
#ifdef UA_ARCHITECTURE_WIN32
    size_t sendAddrLength;
#else
    socklen_t sendAddrLength;
#endif
} UDP_FD;

typedef enum {
    MULTICASTTYPE_NONE = 0,
    MULTICASTTYPE_IPV4,
    MULTICASTTYPE_IPV6
} MultiCastType;

typedef union {
#if !defined(__linux__)
    struct ip_mreq ipv4;
#else
    struct ip_mreqn ipv4;
#endif
#if UA_IPV6
    struct ipv6_mreq ipv6;
#endif
} MulticastRequest;

static UA_Boolean
isMulticastAddress(const UA_Byte *address, UA_Byte mask, UA_Byte prefix) {
    return (address[0] & mask) == prefix;
}

static MultiCastType
multiCastType(struct addrinfo *info) {
    const UA_Byte *address;
    if(info->ai_family == AF_INET) {
        address = (UA_Byte *)&((struct sockaddr_in *)info->ai_addr)->sin_addr;
        if(isMulticastAddress(address, IPV4_PREFIX_MASK, IPV4_MULTICAST_PREFIX))
            return MULTICASTTYPE_IPV4;
#if UA_IPV6
    } else if(info->ai_family == AF_INET6) {
        address = (UA_Byte *)&((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;
        if(isMulticastAddress(address, IPV6_PREFIX_MASK, IPV6_MULTICAST_PREFIX))
            return MULTICASTTYPE_IPV6;
#endif
    }
    return MULTICASTTYPE_NONE;
}

#ifdef UA_ARCHITECTURE_WIN32

#define ADDR_BUFFER_SIZE 15000 /* recommended size in the MSVC docs */

static UA_StatusCode
setMulticastInterface(const char *netif, struct addrinfo *info,
                      MulticastRequest *req, const UA_Logger *logger) {
    ULONG outBufLen = ADDR_BUFFER_SIZE;
    UA_STACKARRAY(char, addrBuf, ADDR_BUFFER_SIZE);

    /* Get the network interface descriptions */
    ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
        GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
    PIP_ADAPTER_ADDRESSES ifaddr = (IP_ADAPTER_ADDRESSES *)addrBuf;
    DWORD ret = GetAdaptersAddresses(info->ai_family, flags, NULL, ifaddr, &outBufLen);
    if(ret != NO_ERROR) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                     "UDP\t| Interface configuration preparation failed");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Iterate through linked list of network interfaces */
    char sourceAddr[64];
    unsigned int idx = 0;
    for(PIP_ADAPTER_ADDRESSES ifa = ifaddr; ifa != NULL; ifa = ifa->Next) {
        idx = (info->ai_family == AF_INET) ? ifa->IfIndex : ifa->Ipv6IfIndex;

        /* Check if network interface name matches */
        if(strcmp(ifa->AdapterName, netif) == 0)
            goto done;

        /* Check if ip address matches */
        for(PIP_ADAPTER_UNICAST_ADDRESS u = ifa->FirstUnicastAddress; u; u = u->Next) {
            LPSOCKADDR addr = u->Address.lpSockaddr;
            if(addr->sa_family == AF_INET) {
                inet_ntop(AF_INET, &((struct sockaddr_in*)addr)->sin_addr,
                          sourceAddr, sizeof(sourceAddr));
            } else if(addr->sa_family == AF_INET6) {
                inet_ntop(AF_INET6, &((struct sockaddr_in6*)addr)->sin6_addr,
                          sourceAddr, sizeof(sourceAddr));
            } else {
                continue;
            }
            if(strcmp(sourceAddr, netif) == 0)
                goto done;
        }
    }

    /* Not matching interface found */
    UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                 "UDP\t| Interface configuration preparation failed "
                 "(interface %s not found)", netif);
    return UA_STATUSCODE_BADINTERNALERROR;

 done:
    /* Write the interface index */
    if(info->ai_family == AF_INET)
        /* MSVC documentation of struct ip_mreq: To use an interface index of 1
         * would be the same as an IP address of 0.0.0.1. */
        req->ipv4.imr_interface.s_addr = htonl(idx);
#if UA_IPV6
    else /* if(info->ai_family == AF_INET6) */
        req->ipv6.ipv6mr_interface = idx;
#endif
    return UA_STATUSCODE_GOOD;
}

#else

static UA_StatusCode
setMulticastInterface(const char *netif, struct addrinfo *info,
                      MulticastRequest *req, const UA_Logger *logger) {
    UA_RESET_ERRNO;
    struct ifaddrs *ifaddr;
    int ret = getifaddrs(&ifaddr);
    if(ret == -1) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                        "UDP\t| Interface configuration preparation failed "
                        "(getifaddrs error: %s)", errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Iterate over the interfaces */
    unsigned int idx = 0;
    struct ifaddrs *ifa = NULL;
    for(ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if(!ifa->ifa_addr)
            continue;

        /* Does the protocol family match? */
        if(ifa->ifa_addr->sa_family != info->ai_family)
            continue;

#if defined(UA_ARCHITECTURE_WIN32) || defined(__linux__)
        idx = UA_if_nametoindex(ifa->ifa_name);
        if(idx == 0)
            continue;
#endif

        /* Found network interface by name */
        if(strcmp(ifa->ifa_name, netif) == 0)
            break;

        /* Check if the interface name is an IP address that matches */
        UA_RESET_ERRNO;
        char host[NI_MAXHOST];
        ret = getnameinfo(ifa->ifa_addr,
                          (info->ai_family == AF_INET) ?
                          sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
                          host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
        if(ret != 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                            "UDP\t| Interface configuration preparation "
                            "failed (Error: %s).", errno_str));
            freeifaddrs(ifaddr);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        if(strcmp(host, netif) == 0)
            break;
    }

    if(!ifa) {
        freeifaddrs(ifaddr);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Write the interface index */
    if(info->ai_family == AF_INET) {
#if defined(__linux__)
        req->ipv4.imr_ifindex = idx;
#elif defined(__APPLE__)
        struct sockaddr_in *sin = (struct sockaddr_in*)ifa->ifa_addr;
        req->ipv4.imr_interface = sin->sin_addr;
#endif
#if UA_IPV6
    } else { /* if(info->ai_family == AF_INET6) */
        req->ipv6.ipv6mr_interface = idx;
#endif
    }

    freeifaddrs(ifaddr);
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ARCHITECTURE_WIN32 */

static UA_StatusCode
setupMulticastRequest(UA_FD socket, MulticastRequest *req, const UA_KeyValueMap *params,
                      struct addrinfo *info, const UA_Logger *logger) {
    /* Initialize the address information */
    if(info->ai_family == AF_INET) {
        struct sockaddr_in *sin = (struct sockaddr_in *)info->ai_addr;
        req->ipv4.imr_multiaddr = sin->sin_addr;
#if !defined(__linux__)
        req->ipv4.imr_interface.s_addr = htonl(INADDR_ANY); /* default ANY */
#else
        req->ipv4.imr_address.s_addr = htonl(INADDR_ANY); /* default ANY */
        req->ipv4.imr_ifindex = 0;
#endif
#if UA_IPV6
    } else if(info->ai_family == AF_INET6) {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)info->ai_addr;
        req->ipv6.ipv6mr_multiaddr = sin6->sin6_addr;
        req->ipv6.ipv6mr_interface = 0; /* default ANY interface */
#endif
    } else {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                     "UDP\t| Multicast configuration failed: Unknown protocol family");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Was an interface (or local IP address) defined? */
    const UA_String *netif = (const UA_String*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_INTERFACE].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(!netif) {
        UA_LOG_INFO(logger, UA_LOGCATEGORY_NETWORK,
                    "UDP %u\t| No network interface defined for multicast. "
                    "The first suitable network interface is used.",
                    (unsigned)socket);
        return UA_STATUSCODE_GOOD;
    }

    /* Set the interface index */
    UA_STACKARRAY(char, interfaceAsChar, sizeof(char) * netif->length + 1);
    memcpy(interfaceAsChar, netif->data, netif->length);
    interfaceAsChar[netif->length] = 0;
    return setMulticastInterface(interfaceAsChar, info, req, logger);
}

/* Retrieves hostname and port from given key value parameters.
 *
 * @param[in] params the parameter map to retrieve from
 * @param[out] hostname the retrieved hostname when present, NULL otherwise
 * @param[out] portStr the retrieved port when present, NULL otherwise
 * @param[in] logger the logger to log information
 * @return -1 upon error, 0 if there was no host or port parameter, 1 if
 *         host and port are present */
static int
getHostAndPortFromParams(const UA_KeyValueMap *params, char *hostname,
                         char *portStr, const UA_Logger *logger) {
    /* Prepare the port parameter as a string */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* checked before */
    mp_snprintf(portStr, UA_MAXPORTSTR_LENGTH, "%d", *port);

    /* Prepare the hostname string */
    const UA_String *host = (const UA_String*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(!host) {
        UA_LOG_DEBUG(logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| No address configured");
        return -1;
    }
    if(host->length >= UA_MAXHOSTNAME_LENGTH) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_EVENTLOOP,
                     "UDP\t| Open UDP Connection: Hostname too long, aborting");
        return -1;
    }
    strncpy(hostname, (const char*)host->data, host->length);
    hostname[host->length] = 0;
    return 1;
}

static int
getConnectionInfoFromParams(const UA_KeyValueMap *params,
                            char *hostname, char *portStr,
                            struct addrinfo **info, const UA_Logger *logger) {
    int foundParams = getHostAndPortFromParams(params, hostname, portStr, logger);
    if(foundParams < 0)
        return -1;

    /* Create the socket description from the connectString
     * TODO: Make this non-blocking */
    UA_RESET_ERRNO;
    struct addrinfo hints;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    int error = UA_getaddrinfo(hostname, portStr, &hints, info);
    if(error != 0) {
#ifdef UA_ARCHITECTURE_WIN32
        UA_LOG_SOCKET_ERRNO_GAI_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP\t| Lookup of %s failed with error %d - %s",
                           hostname, error, errno_str));
#else
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| Lookup of %s failed with error %s",
                       hostname, gai_strerror(error));
#endif
        return -1;
    }
    return 1;
}

/* Set loop back data to your host */
static UA_StatusCode
setLoopBackData(UA_SOCKET sockfd, UA_Boolean enableLoopback,
                int ai_family, const UA_Logger *logger) {
    UA_RESET_ERRNO;
    /* The loopback option has a different integer size between IPv4 and IPv6.
     * Some operating systems (e.g. OpenBSD) handle this very strict. Hence the
     * different "enable" variables below are required. */
    int retcode;
#if UA_IPV6
    if(ai_family == AF_INET6) {
        unsigned int enable6 = enableLoopback;
        retcode = UA_setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
                                &enable6, sizeof(enable6));
    } else
#endif
    {
        unsigned char enable = enableLoopback;
        retcode = UA_setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
                                &enable, sizeof (enable));
    }
    if(retcode < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Loopback setup failed: "
                         "Cannot set socket option IP_MULTICAST_LOOP. Error: %s",
                         (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setTimeToLive(UA_SOCKET sockfd, UA_UInt32 messageTTL,
              int ai_family, const UA_Logger *logger) {
    UA_RESET_ERRNO;
    /* Set Time to live (TTL). Value of 1 prevent forward beyond the local network. */
#if UA_IPV6
    if(UA_setsockopt(sockfd,
                     ai_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP,
                     ai_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL,
                     (const char *)&messageTTL,
                     sizeof(messageTTL)) < 0)
#else
    if(UA_setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
                     (const char *)&messageTTL,
                     sizeof(messageTTL)) < 0)
#endif
    {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP %u\t| Time to live setup failed: "
                           "Cannot set socket option IP_MULTICAST_TTL. Error: %s",
                           (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setReuseAddress(UA_SOCKET sockfd, UA_Boolean enableReuse, const UA_Logger *logger) {
    /* Set reuse address -> enables sharing of the same listening address on
     * different sockets */
    UA_RESET_ERRNO;
    int enableReuseVal = (enableReuse) ? 1 : 0;
    if(UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                     (const char*)&enableReuseVal, sizeof(enableReuseVal)) < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP %u\t| Reuse address setup failed: "
                           "Cannot set socket option SO_REUSEADDR. Error: %s",
                           (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

#ifdef __linux__
static UA_StatusCode
setSocketPriority(UA_SOCKET sockfd, UA_UInt32 socketPriority,
                  const UA_Logger *logger) {
    UA_RESET_ERRNO;
    int prio = (int)socketPriority;
    if(UA_setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(int)) < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Socket priority setup failed: "
                         "Cannot set socket option SO_PRIORITY. Error: %s",
                         (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
setConnectionConfig(UA_FD socket, const UA_KeyValueMap *params,
                    int ai_family, const UA_Logger *logger) {
    /* Set socket config that is always set */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_EventLoopPOSIX_setNonBlocking(socket);
    res |= UA_EventLoopPOSIX_setNoSigPipe(socket);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Some Linux distributions have net.ipv6.bindv6only not activated. So
     * sockets can double-bind to IPv4 and IPv6. This leads to problems. Use
     * AF_INET6 sockets only for IPv6. */
#if UA_IPV6
    int optval = 1;
    if(ai_family == AF_INET6 &&
       UA_setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY,
                     (const char*)&optval, sizeof(optval)) == -1) {
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                       "UDP %u\t| Could not set an IPv6 socket to IPv6 only, closing",
                       (unsigned)socket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }
#endif

    UA_RESET_ERRNO;

    /* Set socket settings from the parameters */
    const UA_UInt32 *messageTTL = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_TTL].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(messageTTL)
        res |= setTimeToLive(socket, *messageTTL, ai_family, logger);

    const UA_Boolean *enableLoopback = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_LOOPBACK].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(enableLoopback)
        res |= setLoopBackData(socket, *enableLoopback, ai_family, logger);

    const UA_Boolean *enableReuse = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_REUSE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(enableReuse)
        res |= setReuseAddress(socket, *enableReuse, logger);

#ifdef __linux__
    const UA_UInt32 *socketPriority = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_SOCKPRIO].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(socketPriority)
        res |= setSocketPriority(socket, *socketPriority, logger);
#endif

    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP\t| Could not set socket options: %s", errno_str));
    }
    return res;
}

static UA_StatusCode
setupListenMultiCast(UA_FD fd, struct addrinfo *info, const UA_KeyValueMap *params,
                     MultiCastType multiCastType, const UA_Logger *logger) {
    MulticastRequest req;
    UA_StatusCode res = setupMulticastRequest(fd, &req, params, info, logger);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_RESET_ERRNO;
    int result = -1;
    if(info->ai_family == AF_INET && multiCastType == MULTICASTTYPE_IPV4) {
        result = UA_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                               &req.ipv4, sizeof(req.ipv4));
#if UA_IPV6
    } else if(info->ai_family == AF_INET6 && multiCastType == MULTICASTTYPE_IPV6) {
        result = UA_setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                               &req.ipv6, sizeof(req.ipv6));
#endif
    }

    if(result < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Cannot set socket for multicast receiving. Error: %s",
                         (unsigned)fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setupSendMultiCast(UA_FD fd, struct addrinfo *info, const UA_KeyValueMap *params,
                   MultiCastType multiCastType, const UA_Logger *logger) {
    MulticastRequest req;
    UA_StatusCode res = setupMulticastRequest(fd, &req, params, info, logger);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_RESET_ERRNO;
    int result = -1;
    if(info->ai_family == AF_INET && multiCastType == MULTICASTTYPE_IPV4) {
#ifdef UA_ARCHITECTURE_WIN32
        result = UA_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
                            (const char *)&req.ipv4.imr_interface,
                            sizeof(struct in_addr));
#elif defined(__APPLE__)
        result = UA_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
                            &req.ipv4.imr_interface, sizeof(struct in_addr));
#else
        result = UA_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
                            &req.ipv4, sizeof(req.ipv4));
#endif
#if UA_IPV6
    } else if(info->ai_family == AF_INET6 && multiCastType == MULTICASTTYPE_IPV6) {
        result = UA_setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                            (const char *)
                            &req.ipv6.ipv6mr_interface, sizeof(req.ipv6.ipv6mr_interface));
#endif
    }

    if(result < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Cannot set socket for multicast sending. Error: %s",
                         (unsigned)fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

/* Test if the ConnectionManager can be stopped */
static void
UDP_checkStopped(UA_POSIXConnectionManager *pcm) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);

    if(pcm->fdsSize == 0 &&
       pcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING) {
        UA_LOG_DEBUG(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| All sockets closed, the EventLoop has stopped");
        pcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
    }
}

/* This method must not be called from the application directly, but from within
 * the EventLoop. Otherwise we cannot be sure whether the file descriptor is
 * still used after calling close. */
static void
UDP_close(UA_POSIXConnectionManager *pcm, UDP_FD *conn) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Closing connection",
                 (unsigned)conn->rfd.fd);

    /* Deregister from the EventLoop */
    UA_EventLoopPOSIX_deregisterFD(el, &conn->rfd);

    /* Deregister internally */
    ZIP_REMOVE(UA_FDTree, &pcm->fds, &conn->rfd);
    UA_assert(pcm->fdsSize > 0);
    pcm->fdsSize--;

    /* Signal closing to the application */
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_CLOSING,
                        &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);

    /* Close the socket */
    UA_RESET_ERRNO;
    int ret = UA_close(conn->rfd.fd);
    if(ret == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "UDP %u\t| Socket closed", (unsigned)conn->rfd.fd);
    } else {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "UDP %u\t| Could not close the socket (%s)",
                          (unsigned)conn->rfd.fd, errno_str));
    }

    UA_free(conn);

    /* Stop if the ucm is stopping and this was the last open socket */
    UDP_checkStopped(pcm);
}

static void
UDP_delayedClose(void *application, void *context) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UDP_FD *conn = (UDP_FD*)context;
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "UDP %u\t| Delayed closing of the connection",
                 (unsigned)conn->rfd.fd);
    UA_LOCK(&el->elMutex);
    UDP_close(pcm, conn);
    UA_UNLOCK(&el->elMutex);
}

/* Gets called when a socket receives data or closes */
static void
UDP_connectionSocketCallback(UA_POSIXConnectionManager *pcm, UDP_FD *conn,
                             short event) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Activity on the socket",
                 (unsigned)conn->rfd.fd);

    if(event == UA_FDEVENT_ERR) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "UDP %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)conn->rfd.fd, errno_str));
        UDP_close(pcm, conn);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Allocate receive buffer", (unsigned)conn->rfd.fd);

    /* Use the already allocated receive-buffer */
    UA_ByteString response = pcm->rxBuffer;

    /* Receive */
    UA_RESET_ERRNO;
    struct sockaddr_storage source;
#ifndef UA_ARCHITECTURE_WIN32
    socklen_t sourceSize = (socklen_t)sizeof(struct sockaddr_storage);
    ssize_t ret = UA_recvfrom(conn->rfd.fd, (char*)response.data, response.length,
                           MSG_DONTWAIT, (struct sockaddr*)&source, &sourceSize);
#else
    int sourceSize = (int)sizeof(struct sockaddr_storage);
    int ret = UA_recvfrom(conn->rfd.fd, (char*)response.data, (int)response.length,
                       MSG_DONTWAIT, (struct sockaddr*)&source, &sourceSize);
#endif

    /* Receive has failed */
    if(ret <= 0) {
        if(ret < 0 && UA_ERRNO == UA_INTERRUPTED)
            return;

        /* Orderly shutdown of the socket. We can immediately close as no method
         * "below" in the call stack will use the socket in this iteration of
         * the EventLoop. */
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "UDP %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)conn->rfd.fd, errno_str));
        UDP_close(pcm, conn);
        return;
    }

    response.length = (size_t)ret; /* Set the length of the received buffer */

    /* Extract message source and port */
    char sourceAddr[64];
    UA_UInt16 sourcePort;
    switch(source.ss_family) {
        case AF_INET:
            UA_inet_ntop(AF_INET, &((struct sockaddr_in *)&source)->sin_addr,
                    sourceAddr, 64);
            sourcePort = htons(((struct sockaddr_in *)&source)->sin_port);
            break;
        case AF_INET6:
            UA_inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&source)->sin6_addr),
                    sourceAddr, 64);
            sourcePort = htons(((struct sockaddr_in6 *)&source)->sin6_port);
            break;
        default:
            sourceAddr[0] = 0;
            sourcePort = 0;
    }

    UA_String sourceAddrStr = UA_STRING(sourceAddr);
    UA_KeyValuePair kvp[2];
    kvp[0].key = UA_QUALIFIEDNAME(0, "remote-address");
    UA_Variant_setScalar(&kvp[0].value, &sourceAddrStr, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "remote-port");
    UA_Variant_setScalar(&kvp[1].value, &sourcePort, &UA_TYPES[UA_TYPES_UINT16]);
    UA_KeyValueMap kvm = {2, kvp};

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Received message of size %u from %s on port %u",
                 (unsigned)conn->rfd.fd, (unsigned)ret,
                 sourceAddr, sourcePort);

    /* Callback to the application layer */
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_ESTABLISHED,
                        &kvm, response);
}

static UA_StatusCode
UDP_registerListenSocket(UA_POSIXConnectionManager *pcm, UA_UInt16 port,
                         struct addrinfo *info, const UA_KeyValueMap *params,
                         void *application, void *context,
                         UA_ConnectionManager_connectionCallback connectionCallback,
                         UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Get logging information */
    UA_RESET_ERRNO;
    char hoststr[UA_MAXHOSTNAME_LENGTH];
    int get_res = UA_getnameinfo(info->ai_addr, info->ai_addrlen,
                                 hoststr, sizeof(hoststr),
                                 NULL, 0, NI_NUMERICHOST);
    if(get_res != 0) {
        hoststr[0] = 0;
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "UDP\t| Could not resolve the hostname (Error: %s)", errno_str));
        if(validate)
            return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Create the listen socket */
    UA_RESET_ERRNO;
    UA_FD listenSocket = UA_socket(info->ai_family, info->ai_socktype, info->ai_protocol);
    if(listenSocket == UA_INVALID_FD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "UDP\t| Error opening the listen socket for "
                          "\"%s\" on port %u (Error: %s)",
                          (unsigned)listenSocket, hoststr, port, errno_str));
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Set the socket configuration per the parameters */
    UA_StatusCode res =
        setConnectionConfig(listenSocket, params,
                            info->ai_family, el->eventLoop.logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_close(listenSocket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Are we going to prepare a socket for multicast? */
    MultiCastType mc = multiCastType(info);

    /* Bind socket to the address */
    UA_RESET_ERRNO;
#ifdef UA_ARCHITECTURE_WIN32
    /* On windows we need to bind the socket to INADDR_ANY before registering
     * for the multicast group */
    int ret = -1;
    if(mc != MULTICASTTYPE_NONE) {
        if(info->ai_family == AF_INET) {
            struct sockaddr_in *orig = (struct sockaddr_in *)info->ai_addr;
            struct sockaddr_in sin;
            memset(&sin, 0, sizeof(sin));
            sin.sin_family = AF_INET;
            sin.sin_addr.s_addr = htonl(INADDR_ANY);
            sin.sin_port = orig->sin_port;
            ret = bind(listenSocket, (struct sockaddr*)&sin, sizeof(sin));
        } else if(info->ai_family == AF_INET6) {
            struct sockaddr_in6 *orig = (struct sockaddr_in6 *)info->ai_addr;
            struct sockaddr_in6 sin6;
            memset(&sin6, 0, sizeof(sin6));
            sin6.sin6_family = AF_INET6;
            sin6.sin6_addr = in6addr_any;
            sin6.sin6_port = orig->sin6_port;
            ret = bind(listenSocket, (struct sockaddr*)&sin6, sizeof(sin6));
        }
    } else {
        ret = UA_bind(listenSocket, info->ai_addr, (socklen_t)info->ai_addrlen);
    }
#else
    int ret = UA_bind(listenSocket, info->ai_addr, (socklen_t)info->ai_addrlen);
#endif

    /* Get the port being used if dynamic porting was used */
    if(port == 0) {
        struct sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        socklen_t len = sizeof(sin);
        if(getsockname(listenSocket, (struct sockaddr *)&sin, &len) != 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
                UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "UDP %u\t| getsockname failed (%s)",
                            (unsigned)listenSocket, errno_str));
            UA_close(listenSocket);
            return UA_STATUSCODE_BADCONNECTIONREJECTED;
        }
        port = ntohs(sin.sin_port);
    }

    if(ret < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                           "UDP\t| Failed to bind listen socket for \"%s\" on port %u "
                           "(Error: %s)", hoststr, port, errno_str));
        UA_close(listenSocket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Enable multicast if this is a multicast address */
    if(mc != MULTICASTTYPE_NONE) {
        UA_RESET_ERRNO;
        res = setupListenMultiCast(listenSocket, info, params, mc,
                                   (validate) ? NULL : el->eventLoop.logger);
        if(res != UA_STATUSCODE_GOOD) {
            if(!validate) {
                UA_LOG_SOCKET_ERRNO_GAI_WRAP(
                   UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger,
                                  UA_LOGCATEGORY_NETWORK,
                                  "UDP\t| Failed to set up multicast for \"%s\" on port %u (%s)",
                                  hoststr, port, errno_str));
            } else {
                UA_LOG_SOCKET_ERRNO_GAI_WRAP(
                   UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                                  "UDP\t| Failed to validate multicast for \"%s\" on port %u (%s)",
                                  hoststr, port, errno_str));
            }
            UA_close(listenSocket);
            return res;
        }
    }

    /* Validation is complete - close and return */
    if(validate) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "UDP\t| Listen socket for \"%s\" on port %u validated", hoststr, port);
        UA_close(listenSocket);
        return UA_STATUSCODE_GOOD;
    }

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "UDP %u\t| New listen socket for \"%s\" on port %u",
                (unsigned)listenSocket, hoststr, port);

    /* Allocate the UA_RegisteredFD */
    UDP_FD *newudpfd = (UDP_FD*)UA_calloc(1, sizeof(UDP_FD));
    if(!newudpfd) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP %u\t| Error allocating memory for the socket, closing",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    newudpfd->rfd.fd = listenSocket;
    newudpfd->rfd.es = &pcm->cm.eventSource;
    newudpfd->rfd.listenEvents = UA_FDEVENT_IN;
    newudpfd->rfd.eventSourceCB = (UA_FDCallback)UDP_connectionSocketCallback;
    newudpfd->applicationCB = connectionCallback;
    newudpfd->application = application;
    newudpfd->context = context;

    /* Register in the EventLoop */
    res = UA_EventLoopPOSIX_registerFD(el, &newudpfd->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP %u\t| Error registering the socket, closing",
                       (unsigned)listenSocket);
        UA_free(newudpfd);
        UA_close(listenSocket);
        return res;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newudpfd->rfd);
    pcm->fdsSize++;

    /* Register the listen socket in the application */
    connectionCallback(&pcm->cm, (uintptr_t)newudpfd->rfd.fd,
                       application, &newudpfd->context,
                       UA_CONNECTIONSTATE_ESTABLISHED,
                       &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_registerListenSockets(UA_POSIXConnectionManager *pcm, const char *hostname,
                          UA_UInt16 port, const UA_KeyValueMap *params,
                          void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);

    /* Get all the interface and IPv4/6 combinations for the configured hostname */
    struct addrinfo hints, *res;
    memset(&hints, 0, sizeof hints);
#if UA_IPV6
    hints.ai_family = AF_UNSPEC; /* Allow IPv4 and IPv6 */
#else
    hints.ai_family = AF_INET;   /* IPv4 only */
#endif
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_flags = AI_PASSIVE;

    /* Set up the port string */
    char portstr[6];
    mp_snprintf(portstr, 6, "%d", port);

    UA_RESET_ERRNO;
    int retcode = UA_getaddrinfo(hostname, portstr, &hints, &res);
    if(retcode != 0) {
#ifdef UA_ARCHITECTURE_WIN32
        UA_LOG_SOCKET_ERRNO_GAI_WRAP(
           UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger,
                          UA_LOGCATEGORY_NETWORK,
                          "UDP\t| getaddrinfo lookup for \"%s\" on port %u failed (%s)",
                          hostname, port, errno_str));
#else
        UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| getaddrinfo lookup for \"%s\" on port %u failed (%s)",
                       hostname, port, gai_strerror(retcode));
#endif
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Add listen sockets */
    struct addrinfo *ai = res;
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    while(ai) {
        rv = UDP_registerListenSocket(pcm, port, ai, params, application,
                                      context, connectionCallback, validate);
        if(rv != UA_STATUSCODE_GOOD)
            break;
        ai = ai->ai_next;
    }
    UA_freeaddrinfo(res);
    return rv;
}

/* Close the connection via a delayed callback */
static void
UDP_shutdown(UA_ConnectionManager *cm, UA_RegisteredFD *rfd) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    if(rfd->dc.callback) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP %u\t| Cannot close - already closing",
                     (unsigned)rfd->fd);
        return;
    }

    /* Shutdown the socket to cancel the current select/epoll */
    UA_shutdown(rfd->fd, UA_SHUT_RDWR);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Shutdown called", (unsigned)rfd->fd);

    UA_DelayedCallback *dc = &rfd->dc;
    dc->callback = UDP_delayedClose;
    dc->application = cm;
    dc->context = rfd;

    /* Adding a delayed callback does not take a lock */
    UA_EventLoopPOSIX_addDelayedCallback((UA_EventLoop*)el, dc);
}

static UA_StatusCode
UDP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
    UA_FD fd = (UA_FD)connectionId;

    UA_LOCK(&el->elMutex);
    UA_RegisteredFD *rfd = ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!rfd) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| Cannot close UDP connection %u - not found",
                       (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UDP_shutdown(cm, rfd);
    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
                       const UA_KeyValueMap *params,
                       UA_ByteString *buf) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;

    UA_LOCK(&el->elMutex);

    /* Look up the registered UDP socket */
    UA_FD fd = (UA_FD)connectionId;
    UDP_FD *conn = (UDP_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!conn) {
        UA_UNLOCK(&el->elMutex);
        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Send the full buffer. This may require several calls to send */
    size_t nWritten = 0;
    do {
        ssize_t n = 0;
        do {
            UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Attempting to send", (unsigned)connectionId);

            /* Prevent OS signals when sending to a closed socket */
            UA_RESET_ERRNO;
            int flags = MSG_NOSIGNAL;
            size_t bytes_to_send = buf->length - nWritten;
            n = UA_sendto((UA_FD)connectionId, (const char*)buf->data + nWritten,
                          bytes_to_send, flags, (struct sockaddr*)&conn->sendAddr,
                          conn->sendAddrLength);
            if(n < 0) {
                /* An error we cannot recover from? */
                if(UA_ERRNO != UA_INTERRUPTED &&
                   UA_ERRNO != UA_WOULDBLOCK &&
                   UA_ERRNO != UA_AGAIN) {
                    UA_LOG_SOCKET_ERRNO_WRAP(
                       UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                                    "UDP %u\t| Send failed with error %s",
                                    (unsigned)connectionId, errno_str));
                    UA_UNLOCK(&el->elMutex);
                    UDP_shutdownConnection(cm, connectionId);
                    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                    return UA_STATUSCODE_BADCONNECTIONCLOSED;
                }

                /* Poll for the socket resources to become available and retry
                 * (blocking) */
                int poll_ret;
                struct pollfd tmp_poll_fd;
                tmp_poll_fd.fd = (UA_FD)connectionId;
                tmp_poll_fd.events = UA_POLLOUT;
                do {
                    UA_RESET_ERRNO;
                    poll_ret = UA_poll(&tmp_poll_fd, 1, 100);
                    if(poll_ret < 0 && UA_ERRNO != UA_INTERRUPTED) {
                        UA_LOG_SOCKET_ERRNO_WRAP(
                           UA_LOG_ERROR(el->eventLoop.logger,
                                        UA_LOGCATEGORY_NETWORK,
                                        "UDP %u\t| Send failed with error %s",
                                        (unsigned)connectionId, errno_str));
                        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                        UDP_shutdown(cm, &conn->rfd);
                        UA_UNLOCK(&el->elMutex);
                        return UA_STATUSCODE_BADCONNECTIONCLOSED;
                    }
                } while(poll_ret <= 0);
            }
        } while(n < 0);
        nWritten += (size_t)n;
    } while(nWritten < buf->length);

    /* Free the buffer */
    UA_UNLOCK(&el->elMutex);
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
registerSocketAndDestinationForSend(const UA_KeyValueMap *params,
                                    const char *hostname, struct addrinfo *info,
                                    int error, UDP_FD *ufd, UA_FD *sock,
                                    const UA_Logger *logger, UA_Boolean validate) {
    UA_RESET_ERRNO;
    UA_FD newSock = UA_socket(info->ai_family, info->ai_socktype, info->ai_protocol);
    *sock = newSock;
    if(newSock == UA_INVALID_FD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP\t| Could not create socket to connect to %s (%s)",
                           hostname, errno_str));
        return UA_STATUSCODE_BADDISCONNECT;
    }
    UA_StatusCode res = setConnectionConfig(newSock, params, info->ai_family, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_close(newSock);
        return res;
    }

    /* Prepare socket for multicast */
    MultiCastType mc = multiCastType(info);
    if(mc != MULTICASTTYPE_NONE) {
        res = setupSendMultiCast(newSock, info, params, mc, (validate) ? NULL : logger);
        if(res != UA_STATUSCODE_GOOD) {
            UA_close(newSock);
            return res;
        }
    }

    memcpy(&ufd->sendAddr, info->ai_addr, info->ai_addrlen);
    ufd->sendAddrLength = info->ai_addrlen;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_openSendConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                       void *application, void *context,
                       UA_ConnectionManager_connectionCallback connectionCallback,
                       UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Get the connection parameters */
    char hostname[UA_MAXHOSTNAME_LENGTH];
    char portStr[UA_MAXPORTSTR_LENGTH];
    struct addrinfo *info = NULL;

    int error = getConnectionInfoFromParams(params, hostname,
                                            portStr, &info, el->eventLoop.logger);
    if(error < 0 || info == NULL) {
        if(info != NULL) {
            UA_freeaddrinfo(info);
        }
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| Opening a connection failed");
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP\t| Open a connection to \"%s\" on port %s", hostname, portStr);

    /* Allocate the UA_RegisteredFD */
    UDP_FD *conn = (UDP_FD*)UA_calloc(1, sizeof(UDP_FD));
    if(!conn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| Error allocating memory for the socket, closing");
        UA_freeaddrinfo(info);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Create a socket and register the destination address from the provided parameters */
    UA_RESET_ERRNO;
    UA_FD newSock = UA_INVALID_FD;
    UA_StatusCode res =
        registerSocketAndDestinationForSend(params, hostname, info,
                                            error, conn, &newSock,
                                            el->eventLoop.logger, validate);
    UA_freeaddrinfo(info);
    if(validate && res == UA_STATUSCODE_GOOD) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| Connection parameters to \"%s\" on port %s have been validated",
                     hostname, portStr);
        UA_close(newSock);
        UA_free(conn);
        return UA_STATUSCODE_GOOD;
    }
    if(res != UA_STATUSCODE_GOOD) {
        if(!validate) {
            UA_LOG_SOCKET_ERRNO_WRAP(
                UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                             "UDP\t| Connection to \"%s\" on port %s could not be opened "
                             "with error: %s", hostname, portStr, errno_str));
        } else {
            UA_LOG_SOCKET_ERRNO_WRAP(
                UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                             "UDP\t| Invalid connection parameters to \"%s\" on "
                             "port %s (Error: %s)", hostname, portStr, errno_str));
        }
        UA_free(conn);
        return res;
    }

    conn->rfd.fd = newSock;
    conn->rfd.listenEvents = 0;
    conn->rfd.es = &pcm->cm.eventSource;
    conn->rfd.eventSourceCB = (UA_FDCallback)UDP_connectionSocketCallback;
    conn->applicationCB = connectionCallback;
    conn->application = application;
    conn->context = context;

    /* Register the fd to trigger when output is possible (the connection is open) */
    res = UA_EventLoopPOSIX_registerFD(el, &conn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| Registering the socket for %s failed", hostname);
        UA_close(newSock);
        UA_free(conn);
        return res;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &conn->rfd);
    pcm->fdsSize++;

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "UDP %u\t| New connection to \"%s\" on port %s",
                (unsigned)newSock, hostname, portStr);

    /* Signal the connection as opening. The connection fully opens in the next
     * iteration of the EventLoop */
    connectionCallback(&pcm->cm, (uintptr_t)newSock, application,
                       &conn->context, UA_CONNECTIONSTATE_ESTABLISHED,
                       &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_openReceiveConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                          void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Get the port */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* checked before */

    /* Get the hostname configuration */
    const UA_Variant *addrs =
        UA_KeyValueMap_get(params, udpConnectionParams[UDP_PARAMINDEX_ADDR].name);
    size_t addrsSize = 0;
    if(addrs) {
        UA_assert(addrs->type == &UA_TYPES[UA_TYPES_STRING]);
        if(UA_Variant_isScalar(addrs))
            addrsSize = 1;
        else
            addrsSize = addrs->arrayLength;
    }

    /* No hostname configured -> listen on all interfaces */
    if(addrsSize == 0) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| Listening on all interfaces");
        return UDP_registerListenSockets(pcm, NULL, *port, params, application,
                                         context, connectionCallback, validate);
    }

    /* Iterate over the configured hostnames */
    UA_String *hostStrings = (UA_String*)addrs->data;
    for(size_t i = 0; i < addrsSize; i++) {
        char hn[UA_MAXHOSTNAME_LENGTH];
        if(hostStrings[i].length >= sizeof(hn))
            continue;
        memcpy(hn, hostStrings[i].data, hostStrings->length);
        hn[hostStrings->length] = '\0';
        UA_StatusCode rv =
            UDP_registerListenSockets(pcm, hn, *port, params, application,
                                      context, connectionCallback, validate);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
                   void *application, void *context,
                   UA_ConnectionManager_connectionCallback connectionCallback) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STARTED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| Cannot open a connection for a "
                     "ConnectionManager that is not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "UDP",
                                        udpConnectionParams,
                                        UDP_PARAMETERSSIZE, params);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&el->elMutex);
        return res;
    }

    UA_Boolean validate = false;
    const UA_Boolean *validationValue = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_VALIDATE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(validationValue)
        validate = *validationValue;

    UA_Boolean listen = false;
    const UA_Boolean *listenValue = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_LISTEN].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(listenValue)
        listen = *listenValue;

    if(listen) {
        res = UDP_openReceiveConnection(pcm, params, application, context,
                                        connectionCallback, validate);
    } else {
        res = UDP_openSendConnection(pcm, params, application, context,
                                     connectionCallback, validate);
    }
    UA_UNLOCK(&el->elMutex);
    return res;
}

static UA_StatusCode
UDP_eventSourceStart(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| To start the ConnectionManager, "
                     "it has to be registered in an EventLoop and not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "UDP",
                                        udpManagerParams, UDP_MANAGERPARAMS,
                                        &cm->eventSource.params);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Allocate the rx buffer */
    res = UA_EventLoopPOSIX_allocateStaticBuffers(pcm);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Set the EventSource to the started state */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;

 finish:
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void *
UDP_shutdownCB(void *application, UA_RegisteredFD *rfd) {
    UA_ConnectionManager *cm = (UA_ConnectionManager*)application;
    UDP_shutdown(cm, rfd);
    return NULL;
}

static void
UDP_eventSourceStop(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    (void)el;
    UA_LOCK(&el->elMutex);

    UA_LOG_DEBUG(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                 "UDP\t| Shutting down the ConnectionManager");

    /* Prevent new connections to open */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;

    /* Shutdown all existing connection */
    ZIP_ITER(UA_FDTree, &pcm->fds, UDP_shutdownCB, cm);

    /* Check if stopped once more (also checking inside UDP_close, but there we
     * don't check if there is no rfd at all) */
    UDP_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
UDP_eventSourceDelete(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(cm->eventSource.state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "UDP\t| The EventSource must be stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_ByteString_clear(&pcm->rxBuffer);
    UA_ByteString_clear(&pcm->txBuffer);
    UA_KeyValueMap_clear(&cm->eventSource.params);
    UA_String_clear(&cm->eventSource.name);
    UA_free(cm);

    return UA_STATUSCODE_GOOD;
}

static const char *udpName = "udp";

UA_ConnectionManager *
UA_ConnectionManager_new_POSIX_UDP(const UA_String eventSourceName) {
    UA_POSIXConnectionManager *cm = (UA_POSIXConnectionManager*)
        UA_calloc(1, sizeof(UA_POSIXConnectionManager));
    if(!cm)
        return NULL;

    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))UDP_eventSourceStart;
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))UDP_eventSourceStop;
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))UDP_eventSourceDelete;
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)udpName);
    cm->cm.openConnection = UDP_openConnection;
    cm->cm.allocNetworkBuffer = UA_EventLoopPOSIX_allocNetworkBuffer;
    cm->cm.freeNetworkBuffer = UA_EventLoopPOSIX_freeNetworkBuffer;
    cm->cm.sendWithConnection = UDP_sendWithConnection;
    cm->cm.closeConnection = UDP_shutdownConnection;
    return &cm->cm;
}

#endif

/**** amalgamated original file "/arch/posix/eventloop_posix_eth.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *   Copyright 2018 (c) Kontron Europe GmbH (Author: Rudolf Hoyler)
 *   Copyright 2019-2020 (c) Kalycito Infotech Private Limited
 *   Copyright 2019-2020 (c) Wind River Systems, Inc.
 *   Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *   Copyright 2025 (c) SICK AG (Author: Joerg Fischer)
 */


#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP) && defined(__linux__)

#include <arpa/inet.h> /* htons */
#include <net/ethernet.h> /* ETH_P_*/
#include <linux/if_packet.h>
#include <linux/net_tstamp.h> /* txtime */

/* Configuration parameters */

#define ETH_MANAGERPARAMS 2

static UA_KeyValueRestriction ethManagerParams[ETH_MANAGERPARAMS] = {
    {{0, UA_STRING_STATIC("recv-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("send-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false}
};

#define ETH_PARAMETERSSIZE 15
#define ETH_PARAMINDEX_ADDR 0
#define ETH_PARAMINDEX_LISTEN 1
#define ETH_PARAMINDEX_IFACE 2
#define ETH_PARAMINDEX_ETHERTYPE 3
#define ETH_PARAMINDEX_VID 4
#define ETH_PARAMINDEX_PCP 5
#define ETH_PARAMINDEX_DEI 6
#define ETH_PARAMINDEX_PROMISCUOUS 7
#define ETH_PARAMINDEX_PRIORITY 8
#define ETH_PARAMINDEX_TXTIME_ENABLE 9
#define ETH_PARAMINDEX_TXTIME_FLAGS 10
#define ETH_PARAMINDEX_TXTIME 11
#define ETH_PARAMINDEX_TXTIME_PICO 12
#define ETH_PARAMINDEX_TXTIME_DROP 13
#define ETH_PARAMINDEX_VALIDATE 14

static UA_KeyValueRestriction ethConnectionParams[ETH_PARAMETERSSIZE+1] = {
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], false, true, false},
    {{0, UA_STRING_STATIC("listen")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("interface")}, &UA_TYPES[UA_TYPES_STRING], true, true, false},
    {{0, UA_STRING_STATIC("ethertype")}, &UA_TYPES[UA_TYPES_UINT16], false, true, false},
    {{0, UA_STRING_STATIC("vid")}, &UA_TYPES[UA_TYPES_UINT16], false, true, false},
    {{0, UA_STRING_STATIC("pcp")}, &UA_TYPES[UA_TYPES_BYTE], false, true, false},
    {{0, UA_STRING_STATIC("dei")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("promiscuous")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("priority")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("txtime-enable")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("txtime-flags")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("txtime")}, &UA_TYPES[UA_TYPES_DATETIME], false, true, false},
    {{0, UA_STRING_STATIC("txtime-pico")}, &UA_TYPES[UA_TYPES_UINT16], false, true, false},
    {{0, UA_STRING_STATIC("txtime-drop-late")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    /* Duplicated address parameter with a scalar value required. For the send-socket case. */
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], true, true, false},
};

#define UA_ETH_MAXHEADERLENGTH (2*ETHER_ADDR_LEN)+4+2+2

typedef struct {
    UA_RegisteredFD rfd;

    UA_ConnectionManager_connectionCallback applicationCB;
    void *application;
    void *context;

    struct sockaddr_ll sll;
    /* The Ethernet header to prepend for sending frames is precomputed and reused.
     * The length field (the last 2 byte) is adjusted.
     * - 2 * ETHER_ADDR_LEN: destination and source
     * - 4 byte: VLAN tagging (optional)
     * - 2 byte: EtherType (optional)
     * - 2 byte: length */
    unsigned char header[UA_ETH_MAXHEADERLENGTH];
    unsigned char headerSize;
    unsigned char lengthOffset; /* No length field if zero */

    UA_Boolean txtimeEnabled;
} ETH_FD;

/* The format of a Ethernet address is six groups of hexadecimal digits,
 * separated by hyphens (e.g. 01-23-45-67-89-ab). */
static UA_StatusCode
parseEthAddress(const UA_String *buf, UA_Byte *addr) {
    size_t curr = 0, idx = 0;
    for(; idx < ETHER_ADDR_LEN; idx++) {
        UA_UInt32 value;
        size_t progress = UA_readNumberWithBase(&buf->data[curr],
                                                buf->length - curr, &value, 16);
        if(progress == 0 || value > (long)0xff)
            return UA_STATUSCODE_BADINTERNALERROR;

        addr[idx] = (UA_Byte) value;

        curr += progress;
        if(curr == buf->length)
            break;

        if(buf->data[curr] != '-')
            return UA_STATUSCODE_BADINTERNALERROR;

        curr++; /* skip '-' */
    }

    if(idx != (ETH_ALEN-1))
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

static UA_Boolean
isMulticastEthAddress(const UA_Byte *address) {
    if((address[0] & 1) == 0)
        return false; /* Unicast address */
    for(size_t i = 0; i < ETHER_ADDR_LEN; i++) {
        if(address[i] != 0xff)
            return true; /* Not broadcast address ff-ff-ff-ff-ff-ff */
    }
    return false;
}

static void
setAddrString(unsigned char addrStr[18], unsigned char addr[ETHER_ADDR_LEN]) {
    mp_snprintf((char*)addrStr, 18, "%02x-%02x-%02x-%02x-%02x-%02x",
                addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}

/* Return zero if parsing failed */
static size_t
parseETHHeader(const UA_ByteString *buf,
               unsigned char destAddr[ETHER_ADDR_LEN],
               unsigned char sourceAddr[ETHER_ADDR_LEN],
               UA_UInt16 *etherType, UA_UInt16 *vid,
               UA_Byte *pcp, UA_Boolean *dei) {
    if(buf->length < (2 * ETHER_ADDR_LEN)+2)
        return 0;

    /* Parse "normal" Ethernet header */
    memcpy(destAddr, buf->data, ETHER_ADDR_LEN);
    memcpy(sourceAddr, &buf->data[ETHER_ADDR_LEN], ETHER_ADDR_LEN);
    size_t pos = 2 * ETHER_ADDR_LEN;
    UA_UInt16 length = ntohs(*(UA_UInt16*)&buf->data[pos]);
    pos += 2;

    /* No EtherType and no VLAN */
    if(length <= 1500)
        return pos;

    /* Parse 802.1Q VLAN header */
    if(length == 0x8100) {
        if(buf->length < (2 * ETHER_ADDR_LEN)+2+4)
            return 0;
        pos += 2;
        UA_UInt16 tci = ntohs(*(UA_UInt16*)&buf->data[pos]);
        *pcp = (tci >> 13) & 0x07;
        *dei = (tci >> 12) & 0x01;
        *vid = tci & 0x0FFF;
        pos += 2;
        length = ntohs(*(UA_UInt16*)&buf->data[pos]);
    }

    /* Set the EtherType if it is set */
    if(length > 1500)
        *etherType = length;

    return pos;
}

static unsigned char
setETHHeader(unsigned char *buf,
             unsigned char destAddr[ETHER_ADDR_LEN],
             unsigned char sourceAddr[ETHER_ADDR_LEN],
             UA_UInt16 etherType, UA_UInt16 vid,
             UA_Byte pcp, UA_Boolean dei, unsigned char *lengthOffset) {
    /* Set dest and source address */
    size_t pos = 0;
    memcpy(buf, destAddr, ETHER_ADDR_LEN);
    pos += ETHER_ADDR_LEN;
    memcpy(&buf[pos], sourceAddr, ETHER_ADDR_LEN);
    pos += ETHER_ADDR_LEN;

    /* Set the 802.1Q VLAN header */
    if(vid > 0 && vid != ETH_P_ALL) {
        *(UA_UInt16*)&buf[pos] = htons(0x8100);
        pos += 2;
        UA_UInt16 tci = (UA_UInt16)(((UA_UInt16)pcp  << 13) | ((UA_UInt16)dei  << 12) | ((UA_UInt16)vid));
        *(UA_UInt16*)&buf[pos] = htons(tci);
        pos += 2;
    }

    /* Set the Ethertype or store the offset for the length field */
    if(etherType == 0 || etherType == ETH_P_ALL) {
        *lengthOffset = (unsigned char)pos;
    } else {
        *(UA_UInt16*)&buf[pos] = htons(etherType);
    }
    pos += 2;
    return (unsigned char)pos;
}

static UA_StatusCode
ETH_allocNetworkBuffer(UA_ConnectionManager *cm, uintptr_t connectionId,
                       UA_ByteString *buf, size_t bufSize) {
    /* Get the ETH_FD */
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_FD fd = (UA_FD)connectionId;
    ETH_FD *erfd = (ETH_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!erfd)
        return UA_STATUSCODE_BADCONNECTIONREJECTED;

    /* Allocate the buffer with the hidden Ethernet header in front */
    UA_StatusCode res =
        UA_EventLoopPOSIX_allocNetworkBuffer(cm, connectionId, buf,
                                             bufSize + erfd->headerSize);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
        buf->data   += erfd->headerSize;
        buf->length -= erfd->headerSize;
    }
    return res;
}

static void
ETH_freeNetworkBuffer(UA_ConnectionManager *cm, uintptr_t connectionId,
                      UA_ByteString *buf) {
    /* Get the ETH_FD */
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_FD fd = (UA_FD)connectionId;
    ETH_FD *erfd = (ETH_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!erfd)
        return;

    /* Unhide the Ethernet header and free */
    buf->data   -= erfd->headerSize;
    buf->length += erfd->headerSize;
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
}

/* Test if the ConnectionManager can be stopped */
static void
ETH_checkStopped(UA_POSIXConnectionManager *pcm) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);

    if(pcm->fdsSize == 0 &&
       pcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING) {
        UA_LOG_DEBUG(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| All sockets closed, the EventLoop has stopped");
        pcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
    }
}

/* This method must not be called from the application directly, but from within
 * the EventLoop. Otherwise we cannot be sure whether the file descriptor is
 * still used after calling close. */
static void
ETH_close(UA_POSIXConnectionManager *pcm, ETH_FD *conn) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "ETH %u\t| Closing connection",
                 (unsigned)conn->rfd.fd);

    /* Deregister from the EventLoop */
    UA_EventLoopPOSIX_deregisterFD(el, &conn->rfd);

    /* Deregister internally */
    ZIP_REMOVE(UA_FDTree, &pcm->fds, &conn->rfd);
    UA_assert(pcm->fdsSize > 0);
    pcm->fdsSize--;

    /* Signal closing to the application */
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_CLOSING,
                        &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);

    /* Close the socket */
    UA_RESET_ERRNO;
    int ret = UA_close(conn->rfd.fd);
    if(ret == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "ETH %u\t| Socket closed", (unsigned)conn->rfd.fd);
    } else {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "ETH %u\t| Could not close the socket (%s)",
                          (unsigned)conn->rfd.fd, errno_str));
    }

    /* Don't call free here. This might be done automatically via the delayed
     * callback that calls ETH_close. */
    /* UA_free(rfd); */

    /* Stop if the ucm is stopping and this was the last open socket */
    ETH_checkStopped(pcm);
}

static void
ETH_delayedClose(void *application, void *context) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    ETH_FD *conn = (ETH_FD*)context;
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "ETH %u\t| Delayed closing of the connection",
                 (unsigned)conn->rfd.fd);
    UA_LOCK(&el->elMutex);
    ETH_close(pcm, conn);
    UA_UNLOCK(&el->elMutex);
    UA_free(conn);
}

/* Gets called when a socket receives data or closes */
static void
ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
                             short event) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex);

    ETH_FD *conn = (ETH_FD*)rfd;
    if(event == UA_FDEVENT_ERR) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "ETH %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)rfd->fd, errno_str));
        ETH_close(pcm, conn);
        UA_free(rfd);
        return;
    }

    /* Use the already allocated receive-buffer */
    UA_ByteString response = pcm->rxBuffer;

    /* Receive */
    UA_RESET_ERRNO;
#ifndef UA_ARCHITECTURE_WIN32
    ssize_t ret = UA_recv(rfd->fd, (char*)response.data,
                          response.length, MSG_DONTWAIT);
#else
    int ret = UA_recv(rfd->fd, (char*)response.data,
                      response.length, MSG_DONTWAIT);
#endif

    /* Receive has failed */
    if(ret <= 0) {
        if(ret < 0 && UA_ERRNO == UA_INTERRUPTED)
            return;

        /* Orderly shutdown of the socket. We can immediately close as no method
         * "below" in the call stack will use the socket in this iteration of
         * the EventLoop. */
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "ETH %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)rfd->fd, errno_str));
        ETH_close(pcm, conn);
        UA_free(rfd);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "ETH %u\t| Received message of size %u",
                 (unsigned)rfd->fd, (unsigned)ret);

    response.length = (size_t)ret;

    /* Parse the Ethernet header */
    unsigned char destAddr[ETHER_ADDR_LEN];
    unsigned char sourceAddr[ETHER_ADDR_LEN];
    UA_UInt16 etherType = 0;
    UA_UInt16 vid = 0;
    UA_Byte pcp = 0;
    UA_Boolean dei = 0;
    size_t headerSize = parseETHHeader(&response, destAddr, sourceAddr,
                                       &etherType, &vid, &pcp, &dei);
    if(headerSize == 0)
        return;

    /* Set up the parameter arguments passed to the application */
    unsigned char destAddrBytes[18];
    unsigned char sourceAddrBytes[18];
    setAddrString(destAddrBytes, destAddr);
    setAddrString(sourceAddrBytes, sourceAddr);
    UA_String destAddrStr = {17, destAddrBytes};
    UA_String sourceAddrStr = {17, sourceAddrBytes};

    size_t paramsSize = 2;
    UA_KeyValuePair params[6];
    params[0].key = UA_QUALIFIEDNAME(0, "destination-address");
    UA_Variant_setScalar(&params[0].value, &destAddrStr, &UA_TYPES[UA_TYPES_STRING]);
    params[1].key = UA_QUALIFIEDNAME(0, "source-address");
    UA_Variant_setScalar(&params[1].value, &sourceAddrStr, &UA_TYPES[UA_TYPES_STRING]);

    if(etherType > 0) {
        params[2].key = UA_QUALIFIEDNAME(0, "ethertype");
        UA_Variant_setScalar(&params[1].value, &etherType, &UA_TYPES[UA_TYPES_UINT16]);
        paramsSize++;
    }

    if(vid > 0) {
        params[paramsSize].key = UA_QUALIFIEDNAME(0, "vid");
        UA_Variant_setScalar(&params[paramsSize].value, &vid, &UA_TYPES[UA_TYPES_UINT16]);
        params[paramsSize+1].key = UA_QUALIFIEDNAME(0, "pcp");
        UA_Variant_setScalar(&params[paramsSize+1].value, &pcp, &UA_TYPES[UA_TYPES_BYTE]);
        params[paramsSize+2].key = UA_QUALIFIEDNAME(0, "dei");
        UA_Variant_setScalar(&params[paramsSize+2].value, &dei, &UA_TYPES[UA_TYPES_BOOLEAN]);
        paramsSize += 3;
    }

    /* Callback to the application layer with the Ethernet header hidden */
    UA_KeyValueMap map = {paramsSize, params};
    response.data += headerSize;
    response.length -= headerSize;
    conn->applicationCB(cm, (uintptr_t)rfd->fd, conn->application, &conn->context,
                        UA_CONNECTIONSTATE_ESTABLISHED, &map, response);
    response.data -= headerSize;
    response.length += headerSize;
}

static UA_StatusCode
ETH_openListenConnection(UA_EventLoopPOSIX *el, ETH_FD *conn,
                         const UA_KeyValueMap *params,
                         int ifindex, UA_UInt16 etherType,
                         UA_Boolean validate) {
    UA_LOCK_ASSERT(&el->elMutex);

    /* Bind the socket to interface and EtherType. Don't receive anything else. */
    struct sockaddr_ll sll;
    memset(&sll, 0, sizeof(struct sockaddr_ll));
    sll.sll_family = AF_PACKET;
    sll.sll_protocol = htons(etherType);
    sll.sll_ifindex = ifindex;
    if(!validate && bind(conn->rfd.fd, (struct sockaddr*)&sll, sizeof(sll)) < 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Immediately register for listen events. Don't have to wait for a
     * connection to open. */
    conn->rfd.listenEvents = UA_FDEVENT_IN;

    /* Set receiving to promiscuous (all target host addresses) */
    UA_RESET_ERRNO;
    const UA_Boolean *promiscuous = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_PROMISCUOUS].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(promiscuous && *promiscuous) {
        struct packet_mreq mreq;
        memset(&mreq, 0, sizeof(struct packet_mreq));
        mreq.mr_ifindex = ifindex;
        mreq.mr_type = PACKET_MR_PROMISC;
        int ret = UA_setsockopt(conn->rfd.fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
                             &mreq, sizeof(mreq));
        if(ret < 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "ETH %u\t| Could not set raw socket to promiscuous mode %s",
                            (unsigned)conn->rfd.fd, errno_str));
            return UA_STATUSCODE_BADINTERNALERROR;
        } else {
            UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "ETH %u\t| The socket was set to promiscuous mode",
                        (unsigned)conn->rfd.fd);
        }
    }

    /* Register for multicast if an address is defined */
    const UA_String *address = (const UA_String*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(address) {
        UA_Byte addr[ETHER_ADDR_LEN];
        UA_StatusCode res = parseEthAddress(address, addr);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "ETH\t| Address for listening cannot be parsed");
            return res;
        }

        if(!isMulticastEthAddress(addr)) {
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "ETH\t| Address for listening is not a multicast address. Ignoring.");
            return UA_STATUSCODE_GOOD;
        }

        UA_RESET_ERRNO;
        struct packet_mreq mreq;
        memset(&mreq, 0, sizeof(struct packet_mreq));
        mreq.mr_ifindex = ifindex;
        mreq.mr_type = PACKET_MR_MULTICAST;
        mreq.mr_alen = ETH_ALEN;
        memcpy(mreq.mr_address, addr, ETHER_ADDR_LEN);
        if(!validate && UA_setsockopt(conn->rfd.fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
                                      (char *)&mreq, sizeof(mreq)) < 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "ETH\t| Registering for multicast failed with error %s",
                            errno_str));
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "ETH %u\t| Opened an Ethernet listen socket",
                (unsigned)conn->rfd.fd);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
ETH_openSendConnection(UA_EventLoopPOSIX *el, ETH_FD *conn, const UA_KeyValueMap *params,
                       UA_Byte source[ETHER_ADDR_LEN], int ifindex, UA_UInt16 etherType) {
    UA_LOCK_ASSERT(&el->elMutex);

    /* Parse the target address (has to exist) */
    const UA_String *address = (const UA_String*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    UA_Byte dest[ETHER_ADDR_LEN];
    UA_StatusCode res = parseEthAddress(address, dest);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| Could not parse the Ethernet address \"%.*s\"",
                     (int)address->length, (char*)address->data);
        return res;
    }

    /* Get the VLAN config */
    UA_UInt16 vid = 0;
    UA_Byte pcp = 0;
    UA_Boolean eid = false;

    const UA_UInt16 *vidp = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_VID].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    if(vidp)
        vid = *vidp;

    const UA_Byte *pcpp = (const UA_Byte*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_PCP].name,
                                 &UA_TYPES[UA_TYPES_BYTE]);
    if(pcpp)
        pcp = *pcpp;

    const UA_Boolean *eidp = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_DEI].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(eidp)
        eid = *eidp;

    /* Store the structure for sendto */
    conn->sll.sll_ifindex = ifindex;
    conn->sll.sll_halen = ETH_ALEN;
    memcpy(conn->sll.sll_addr, dest, ETHER_ADDR_LEN);

    /* Generate the Ethernet header */
    conn->headerSize = setETHHeader(conn->header, dest, source, etherType,
                                    vid, pcp, eid, &conn->lengthOffset);

    /* Set the send priority if defined */
    const UA_Int32 *soPriority = (const UA_Int32*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_PRIORITY].name,
                                 &UA_TYPES[UA_TYPES_INT32]);
    if(soPriority) {
        UA_RESET_ERRNO;
        int prioRes = UA_setsockopt(conn->rfd.fd, SOL_SOCKET, SO_PRIORITY,
                                 soPriority, sizeof(int));
        if(prioRes != 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "UA_setsockopt SO_PRIORITY failed with error %s", errno_str));
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    /* Enable txtime sending */
    const UA_Boolean *txtime_enable = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_ENABLE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);

    if(txtime_enable && *txtime_enable) {
#ifndef SO_TXTIME
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "ETH %u\t| txtime feature not supported",
                       (unsigned)conn->rfd.fd);
#else
        const UA_UInt32 *txtime_flags = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_FLAGS].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);
        UA_RESET_ERRNO;
        struct sock_txtime so_txtime_val;
        memset(&so_txtime_val, 0, sizeof(struct sock_txtime));
        so_txtime_val.clockid = el->clockSourceMonotonic;
        so_txtime_val.flags = SOF_TXTIME_REPORT_ERRORS;
        if(txtime_flags)
            so_txtime_val.flags = *txtime_flags;
        if(UA_setsockopt(conn->rfd.fd, SOL_SOCKET, SO_TXTIME,
                      &so_txtime_val, sizeof(so_txtime_val)) == 0) {
            conn->txtimeEnabled = true;
        } else {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                              "ETH %u\t| Could not enable txtime (%s)",
                              (unsigned)conn->rfd.fd, errno_str));
        }
#endif
    }

    /* Done creating the socket */
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "ETH %u\t| Opened an Ethernet send socket",
                (unsigned)conn->rfd.fd);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
ETH_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
                   void *application, void *context,
                   UA_ConnectionManager_connectionCallback connectionCallback) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;

    UA_LOCK(&el->elMutex);

    /* Listen or send connection? */
    const UA_Boolean *listen = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_LISTEN].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    size_t ethParamRestrictions = ETH_PARAMETERSSIZE;
    if(!listen || !*listen)
        ethParamRestrictions++; /* Use the last restriction only for send connections */

    /* Validate the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "ETH", ethConnectionParams,
                                        ethParamRestrictions, params);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&el->elMutex);
        return res;
    }

    /* Only validate the parameters? */
    UA_Boolean validate = false;
    const UA_Boolean *validateParam = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_VALIDATE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(validateParam)
        validate = *validateParam;

    /* Get the EtherType parameter */
    UA_UInt16 etherType = ETH_P_ALL;
    const UA_UInt16 *etParam =  (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_ETHERTYPE].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    if(etParam)
        etherType = *etParam;

    /* Get the interface index */
    const UA_String *interface = (const UA_String*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_IFACE].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if (interface == NULL) {
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(interface->length >= 128) {
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    char ifname[128];
    if(interface->length)
        memcpy(ifname, interface->data, interface->length);
    ifname[interface->length] = 0;
    int ifindex = (int)if_nametoindex(ifname);
    if(ifindex == 0) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| Could not find the interface %s", ifname);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create the socket and add the basic configuration */
    ETH_FD *conn = NULL;
    UA_FD sockfd;
    if(listen && *listen)
        sockfd = UA_socket(PF_PACKET, SOCK_RAW, htons(etherType));
    else
        sockfd = UA_socket(PF_PACKET, SOCK_RAW, 0); /* Don't receive */
    if(sockfd == -1) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| Could not create a raw Ethernet socket (are you root?)");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* SO_REUSEADDR is unnecessary (and unsupported on some Linux systems):
     * res |= UA_EventLoopPOSIX_setReusable(sockfd); */
    res |= UA_EventLoopPOSIX_setNonBlocking(sockfd);
    res |= UA_EventLoopPOSIX_setNoSigPipe(sockfd);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Create the FD object */
    conn = (ETH_FD*)UA_calloc(1, sizeof(ETH_FD));
    if(!conn) {
        res = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    conn->rfd.fd = sockfd;
    conn->rfd.es = &pcm->cm.eventSource;
    conn->rfd.eventSourceCB = (UA_FDCallback)ETH_connectionSocketCallback;
    conn->context = context;
    conn->application = application;
    conn->applicationCB = connectionCallback;

    /* Configure a listen or a send connection */
    if(!listen || !*listen) {
        /* Get the source address for the interface */
        UA_RESET_ERRNO;
        struct ifreq ifr;
        memcpy(ifr.ifr_name, ifname, interface->length);
        ifr.ifr_name[interface->length] = 0;
        int result = ioctl(conn->rfd.fd, SIOCGIFHWADDR, &ifr);
        if(result == -1) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "ETH %u\t| Cannot get the source address, %s",
                            (unsigned)conn->rfd.fd, errno_str));
            res = UA_STATUSCODE_BADCONNECTIONREJECTED;
            goto cleanup;
        }
        res = ETH_openSendConnection(el, conn, params,
                                     (unsigned char*)ifr.ifr_hwaddr.sa_data,
                                     ifindex, etherType);
    } else {
        res = ETH_openListenConnection(el, conn, params, ifindex, etherType, validate);
    }

    /* Don't actually open or shut down */
    if(validate || res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Register in the EventLoop */
    res = UA_EventLoopPOSIX_registerFD(el, &conn->rfd);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Register locally */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &conn->rfd);
    pcm->fdsSize++;

    /* Register the listen socket in the application */
    connectionCallback(cm, (uintptr_t)sockfd, application, &conn->context,
                       UA_CONNECTIONSTATE_ESTABLISHED, &UA_KEYVALUEMAP_NULL,
                       UA_BYTESTRING_NULL);
    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;

 cleanup:
    UA_close(sockfd);
    UA_free(conn);
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void
ETH_shutdown(UA_POSIXConnectionManager *pcm, ETH_FD *conn) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);

    UA_DelayedCallback *dc = &conn->rfd.dc;
    if(dc->callback) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "ETH %u\t| Cannot close - already closing",
                    (unsigned)conn->rfd.fd);
        return;
    }

    /* Shutdown the socket to cancel the current select/epoll */
    UA_shutdown(conn->rfd.fd, UA_SHUT_RDWR);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "ETH %u\t| Shutdown called", (unsigned)conn->rfd.fd);

    dc->callback = ETH_delayedClose;
    dc->application = pcm;
    dc->context = conn;

    /* Adding a delayed callback does not take a lock */
    UA_EventLoopPOSIX_addDelayedCallback((UA_EventLoop*)el, dc);
}

static UA_StatusCode
ETH_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_LOCK(&el->elMutex);

    /* Get the ETH_FD */
    UA_FD fd = (UA_FD)connectionId;
    UA_RegisteredFD *rfd = ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!rfd) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "ETH\t| Cannot close Ethernet connection %u - not found",
                       (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    ETH_shutdown(pcm, (ETH_FD*)rfd);
    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

#ifdef SO_TXTIME
static ssize_t
send_txtime(UA_EventLoopPOSIX *el, ETH_FD *conn, const UA_KeyValueMap *params,
            UA_DateTime txtime, const char *bytes, size_t bytesSize) {
    /* Get additiona parameters */
    const UA_UInt16 *txtime_pico = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_PICO].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    const UA_Boolean *txtime_drop = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_DROP].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
#ifndef SCM_DROP_IF_LATE
    if(txtime_drop) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH %u\t| txtime drop_if_late not supported on the current system",
                     (unsigned)conn->rfd.fd);
        return 0;
    }
#endif


    /* Transform from 100ns since 1601 to ns since the Unix Epoch */
    UA_UInt64 transmission_time = (UA_UInt64)
        (txtime - UA_DATETIME_UNIX_EPOCH) * 100;
    if(txtime_pico)
        transmission_time += (*txtime_pico) / 1000;

    /* Structure for scattering or gathering of input/output */
    struct iovec inputOutputVec;
    inputOutputVec.iov_base = (void*)(uintptr_t)bytes;
    inputOutputVec.iov_len  = bytesSize;

    /* Specify the transmission time in the CMSG. */
    char dataPacket[CMSG_SPACE(sizeof(uint64_t))
#ifdef SCM_DROP_IF_LATE
                    + CMSG_SPACE(sizeof(uint8_t))
#endif
                    ];
    struct msghdr message;
    memset(&message, 0, sizeof(struct msghdr));
    message.msg_control    = dataPacket;
    message.msg_controllen = sizeof(dataPacket);
    message.msg_name       = (struct sockaddr*)&conn->sll;
    message.msg_namelen    = sizeof(conn->sll);
    message.msg_iov        = &inputOutputVec;
    message.msg_iovlen     = 1;

    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&message);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type  = SCM_TXTIME;
    cmsg->cmsg_len   = CMSG_LEN(sizeof(__u64));
    *((__u64*)CMSG_DATA(cmsg)) = transmission_time;

#ifdef SCM_DROP_IF_LATE
    cmsg = CMSG_NXTHDR(&message, cmsg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_DROP_IF_LATE;
    cmsg->cmsg_len = CMSG_LEN(sizeof(uint8_t));
    *((uint8_t*)CMSG_DATA(cmsg)) = (!txtime_drop || *txtime_drop) ? 1: 0;
#endif

    /* Send */
    return sendmsg(conn->rfd.fd, &message, 0);
}
#endif

static UA_StatusCode
ETH_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
                       const UA_KeyValueMap *params, UA_ByteString *buf) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;

    UA_LOCK(&el->elMutex);

    /* Get the ETH_FD */
    UA_FD fd = (UA_FD)connectionId;
    ETH_FD *conn = (ETH_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!conn) {
        UA_UNLOCK(&el->elMutex);
        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Uncover and set the Ethernet header */
    buf->data -= conn->headerSize;
    buf->length += conn->headerSize;
    memcpy(buf->data, conn->header, conn->headerSize);
    if(conn->lengthOffset) {
        UA_UInt16 *ethLength =  (UA_UInt16*)&buf->data[conn->lengthOffset];
        *ethLength = htons((UA_UInt16)(buf->length - conn->headerSize));
    }

    /* Was a txtime configured? */
    const UA_DateTime *txtime = (const UA_DateTime*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_TXTIME].name,
                                 &UA_TYPES[UA_TYPES_DATETIME]);
    if(txtime && !conn->txtimeEnabled) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH %u\t| txtime was not configured for the connection",
                     (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Prevent OS signals when sending to a closed socket */
    int flags = MSG_NOSIGNAL;

    struct pollfd tmp_poll_fd;
    tmp_poll_fd.fd = (UA_FD)connectionId;
    tmp_poll_fd.events = UA_POLLOUT;

    /* Send the full buffer. This may require several calls to send */
    size_t nWritten = 0;
    do {
        ssize_t n = 0;
        do {
            UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "ETH %u\t| Attempting to send", (unsigned)connectionId);
            UA_RESET_ERRNO;
            size_t bytes_to_send = buf->length - nWritten;
#ifdef SO_TXTIME
            if(txtime) {
                n = send_txtime(el, conn, params, *txtime,
                                (const char*)buf->data + nWritten, bytes_to_send);
            } else
#endif
            {
                n = UA_sendto(conn->rfd.fd,
                              (const char*)buf->data + nWritten, bytes_to_send,
                              flags, (struct sockaddr*)&conn->sll, sizeof(conn->sll));
            }
            if(n < 0) {
                /* An error we cannot recover from? */
                if(UA_ERRNO != UA_INTERRUPTED &&
                   UA_ERRNO != UA_WOULDBLOCK &&
                   UA_ERRNO != UA_AGAIN) {
                    UA_LOG_SOCKET_ERRNO_WRAP(
                       UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                                    "ETH %u\t| Send failed with error %s",
                                    (unsigned)connectionId, errno_str));
                    ETH_shutdown(pcm, conn);
                    UA_UNLOCK(&el->elMutex);
                    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                    return UA_STATUSCODE_BADCONNECTIONCLOSED;
                }

                /* Poll for the socket resources to become available and retry
                 * (blocking) */
                int poll_ret;
                do {
                    UA_RESET_ERRNO;
                    poll_ret = UA_poll(&tmp_poll_fd, 1, 100);
                    if(poll_ret < 0 && UA_ERRNO != UA_INTERRUPTED) {
                        UA_LOG_SOCKET_ERRNO_WRAP(
                           UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                                        "ETH %u\t| Send failed with error %s",
                                        (unsigned)connectionId, errno_str));
                        ETH_shutdown(pcm, conn);
                        UA_UNLOCK(&el->elMutex);
                        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                        return UA_STATUSCODE_BADCONNECTIONCLOSED;
                    }
                } while(poll_ret <= 0);
            }
        } while(n < 0);
        nWritten += (size_t)n;
    } while(nWritten < buf->length);

    /* Free the buffer */
    UA_UNLOCK(&el->elMutex);
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
ETH_eventSourceStart(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "To start the Ethernet ConnectionManager, "
                     "it has to be registered in an EventLoop and not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "ETH",
                                        ethManagerParams, ETH_MANAGERPARAMS,
                                        &cm->eventSource.params);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Allocate the rx buffer */
    res = UA_EventLoopPOSIX_allocateStaticBuffers(pcm);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Set the EventSource to the started state */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;

 finish:
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void *
ETH_shutdownCB(void *application, UA_RegisteredFD *rfd) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    ETH_shutdown(pcm, (ETH_FD*)rfd);
    return NULL;
}

static void
ETH_eventSourceStop(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "ETH\t| Shutting down the ConnectionManager");

    /* Prevent new connections to open */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;

    /* Shutdown all existing connection */
    ZIP_ITER(UA_FDTree, &pcm->fds, ETH_shutdownCB, cm);

    /* Check if stopped once more (also checking inside ETH_close, but there we
     * don't check if there is no rfd at all) */
    ETH_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
ETH_eventSourceDelete(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(cm->eventSource.state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "ETH\t| The EventSource must be stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_KeyValueMap_clear(&cm->eventSource.params);
    UA_ByteString_clear(&pcm->rxBuffer);
    UA_ByteString_clear(&pcm->txBuffer);
    UA_String_clear(&cm->eventSource.name);
    UA_free(cm);
    return UA_STATUSCODE_GOOD;
}

static const char *ethName = "eth";

UA_ConnectionManager *
UA_ConnectionManager_new_POSIX_Ethernet(const UA_String eventSourceName) {
    UA_POSIXConnectionManager *cm = (UA_POSIXConnectionManager*)
        UA_calloc(1, sizeof(UA_POSIXConnectionManager));
    if(!cm)
        return NULL;

    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))ETH_eventSourceStart;
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))ETH_eventSourceStop;
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))ETH_eventSourceDelete;
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)ethName);
    cm->cm.openConnection = ETH_openConnection;
    cm->cm.allocNetworkBuffer = ETH_allocNetworkBuffer;
    cm->cm.freeNetworkBuffer = ETH_freeNetworkBuffer;
    cm->cm.sendWithConnection = ETH_sendWithConnection;
    cm->cm.closeConnection = ETH_shutdownConnection;
    return &cm->cm;
}

#endif /* defined(UA_ARCHITECTURE_POSIX) && defined(__linux__) */


/**** amalgamated original file "/arch/posix/eventloop_posix_interrupt.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021, 2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */

#include <signal.h>

#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP) || defined(UA_ARCHITECTURE_WIN32)
/* Different implementation approaches:
 * - Linux: Use signalfd
 * - Other: Use the self-pipe trick (http://cr.yp.to/docs/selfpipe.html) */

typedef struct UA_RegisteredSignal {
#ifdef UA_HAVE_EPOLL
    /* With epoll, register each signal with a socket.
     * This has to be the first element of the struct to allow casting. */
    UA_RegisteredFD rfd;
#endif

    LIST_ENTRY(UA_RegisteredSignal) listPointers;

    UA_InterruptCallback signalCallback;
    void *context;
    int signal; /* POSIX identifier of the interrupt signal */

    UA_Boolean active; /* Signals are only active when the EventLoop is started */
    UA_Boolean triggered;
} UA_RegisteredSignal;

typedef struct {
    UA_InterruptManager im;

    LIST_HEAD(, UA_RegisteredSignal) signals; /* Registered signals */

#ifndef UA_HAVE_EPOLL
    UA_DelayedCallback dc; /* Process all triggered signals */
#endif
} UA_POSIXInterruptManager;

/* The following methods have to be implemented for epoll/self-pipe each. */
static void activateSignal(UA_RegisteredSignal *rs);
static void deactivateSignal(UA_RegisteredSignal *rs);

#ifdef UA_HAVE_EPOLL
#include <sys/signalfd.h>

static void
handlePOSIXInterruptEvent(UA_EventSource *es, UA_RegisteredFD *rfd, short event) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex);

    UA_RegisteredSignal *rs = (UA_RegisteredSignal*)rfd;
    struct signalfd_siginfo fdsi;
    ssize_t s = read(rfd->fd, &fdsi, sizeof(fdsi));
    if(s < (ssize_t)sizeof(fdsi)) {
        /* A problem occured */
        deactivateSignal(rs);
        return;
    }

    /* Signal received */
    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Interrupt %u\t| Received a signal %u",
                 (unsigned)rfd->fd, fdsi.ssi_signo);

    UA_UNLOCK(&el->elMutex);
    rs->signalCallback((UA_InterruptManager *)es, (uintptr_t)rfd->fd,
                       rs->context, &UA_KEYVALUEMAP_NULL);
    UA_LOCK(&el->elMutex);
}

static void
activateSignal(UA_RegisteredSignal *rs) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)rs->rfd.es->eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex);

    if(rs->active)
        return;

    /* Block the normal signal handling */
    UA_RESET_ERRNO;
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, rs->signal);
    int res2 = sigprocmask(SIG_BLOCK, &mask, NULL);
    if(res2 == -1) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Interrupt\t| Could not block the default "
                           "signal handling with an error: %s",
                           errno_str));
        return;
    }

    /* Create the fd */
    UA_RESET_ERRNO;
    UA_FD newfd = signalfd(-1, &mask, 0);
    if(newfd < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Interrupt\t| Could not create a signal file "
                           "description with error: %s",
                           errno_str));
        sigprocmask(SIG_UNBLOCK, &mask, NULL); /* restore signal */
        return;
    }

    rs->rfd.fd = newfd;
    rs->rfd.eventSourceCB = handlePOSIXInterruptEvent;
    rs->rfd.listenEvents = UA_FDEVENT_IN;

    /* Register the fd in the EventLoop */
    UA_StatusCode res = UA_EventLoopPOSIX_registerFD(el, &rs->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Interrupt\t| Could not register the a signal file "
                       "description in the EventLoop");
        UA_close(newfd);
        sigprocmask(SIG_UNBLOCK, &mask, NULL); /* restore signal */
        return;
    }

    rs->active = true;
}

static void
deactivateSignal(UA_RegisteredSignal *rs) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)rs->rfd.es->eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Only dectivate if active */
    if(!rs->active)
        return;
    rs->active = false;

    /* Stop receiving the signal on the FD */
    UA_EventLoopPOSIX_deregisterFD(el, &rs->rfd);

    /* Unblock the signal */
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, (int)rs->signal);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);

    /* Clean up locally */
    UA_close(rs->rfd.fd);
}

#else /* !UA_HAVE_EPOLL */

/* When using signal() a global pointer to the interrupt manager is required.
 * We have no other we to get additional data with the interrupt. */
static UA_POSIXInterruptManager *singletonIM = NULL;

/* Execute all triggered interrupts in a delayed callback by the EventLoop */
static void
executeTriggeredPOSIXInterrupts(UA_POSIXInterruptManager *im, void *_) {
    im->dc.callback = NULL; /* Allow to re-arm the delayed callback */

    UA_RegisteredSignal *rs, *rs_tmp;
    LIST_FOREACH_SAFE(rs, &im->signals, listPointers, rs_tmp) {
        rs->triggered = false;
        rs->signalCallback(&im->im, (uintptr_t)rs->signal,
                           rs->context, &UA_KEYVALUEMAP_NULL);
    }
}

/* Mark the signal entry as triggered and make the EventLoop process it "soon"
 * with a delayed callback. This is an interrupt handler and cannot take a
 * lock. */
static void
triggerPOSIXInterruptEvent(int sig) {
    UA_assert(singletonIM != NULL);

    /* Find the signal */
    UA_RegisteredSignal *rs;
    LIST_FOREACH(rs, &singletonIM->signals, listPointers) {
        if(rs->signal == sig)
            break;
    }
    if(!rs || rs->triggered || !rs->active)
        return;

    /* Mark as triggered */
    rs->triggered = true;

#ifdef UA_ARCHITECTURE_WIN32
    /* On WIN32 we have to re-arm the signal or it will go back to SIG_DFL */
    signal(sig, triggerPOSIXInterruptEvent);
#endif

    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)singletonIM->im.eventSource.eventLoop;

    /* Arm the delayed callback for processing the received signals */
    if(!singletonIM->dc.callback) {
        singletonIM->dc.callback = (UA_Callback)executeTriggeredPOSIXInterrupts;
        singletonIM->dc.application = singletonIM;
        singletonIM->dc.context = NULL;
        UA_EventLoopPOSIX_addDelayedCallback(&el->eventLoop, &singletonIM->dc);
    }

    /* Cancel the EventLoop if it is currently waiting with a timeout */
    UA_EventLoopPOSIX_cancel(el);
}

static void
activateSignal(UA_RegisteredSignal *rs) {
    UA_assert(singletonIM != NULL);
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)singletonIM->im.eventSource.eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Register the signal on the OS level */
    if(rs->active)
        return;

    UA_RESET_ERRNO;
    void (*prev)(int);
    prev = signal(rs->signal, triggerPOSIXInterruptEvent);
    if(prev == SIG_ERR) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(singletonIM->im.eventSource.eventLoop->logger,
                          UA_LOGCATEGORY_EVENTLOOP,
                          "Error registering the signal: %s", errno_str));
        return;
    }

    rs->active = true;
}

static void
deactivateSignal(UA_RegisteredSignal *rs) {
    UA_assert(singletonIM != NULL);
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)singletonIM->im.eventSource.eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex);

    /* Only dectivate if active */
    if(!rs->active)
        return;

    /* Stop receiving the signal */
    signal(rs->signal, SIG_DFL);

    rs->triggered = false;
    rs->active = false;
}

#endif /* !UA_HAVE_EPOLL */

static UA_StatusCode
registerPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle,
                       const UA_KeyValueMap *params,
                       UA_InterruptCallback callback, void *interruptContext) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
    if(!UA_KeyValueMap_isEmpty(params)) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Interrupt\t| Supplied parameters invalid for the "
                     "POSIX InterruptManager");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOCK(&el->elMutex);

    /* Was the signal already registered? */
    int signal = (int)interruptHandle;
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)im;
    UA_RegisteredSignal *rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        if(rs->signal == signal)
            break;
    }
    if(rs) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Interrupt\t| Signal %u already registered",
                       (unsigned)interruptHandle);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create and populate the new context object */
    rs = (UA_RegisteredSignal *)UA_calloc(1, sizeof(UA_RegisteredSignal));
    if(!rs) {
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

#ifdef UA_HAVE_EPOLL
    rs->rfd.es = &im->eventSource;
#endif
    rs->signal = (int)interruptHandle;
    rs->signalCallback = callback;
    rs->context = interruptContext;

    /* Add to the InterruptManager */
    LIST_INSERT_HEAD(&pim->signals, rs, listPointers);

    /* Activate if we are already running */
    if(pim->im.eventSource.state == UA_EVENTSOURCESTATE_STARTED)
        activateSignal(rs);

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static void
deregisterPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
    (void)el;
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)im;
    UA_LOCK(&el->elMutex);

    int signal = (int)interruptHandle;
    UA_RegisteredSignal *rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        if(rs->signal == signal)
            break;
    }
    if(rs) {
        deactivateSignal(rs);
        LIST_REMOVE(rs, listPointers);
        UA_free(rs);
    }

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
startPOSIXInterruptManager(UA_EventSource *es) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(es->state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Interrupt\t| To start the InterruptManager, "
                     "it has to be registered in an EventLoop and not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Interrupt\t| Starting the InterruptManager");

    /* Activate the registered signal handlers */
    UA_RegisteredSignal*rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        activateSignal(rs);
    }

    /* Set the EventSource to the started state */
    es->state = UA_EVENTSOURCESTATE_STARTED;

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static void
stopPOSIXInterruptManager(UA_EventSource *es) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK(&el->elMutex);

    if(es->state != UA_EVENTSOURCESTATE_STARTED) {
        UA_UNLOCK(&el->elMutex);
        return;
    }

    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Interrupt\t| Stopping the InterruptManager");

    /* Close all registered signals */
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
    UA_RegisteredSignal*rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        deactivateSignal(rs);
    }

    /* Immediately set to stopped */
    es->state = UA_EVENTSOURCESTATE_STOPPED;

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
freePOSIXInterruptmanager(UA_EventSource *es) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex);

    if(es->state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Interrupt\t| The EventSource must be stopped "
                     "before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Deactivate and remove all registered signals */
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
    UA_RegisteredSignal *rs, *rs_tmp;
    LIST_FOREACH_SAFE(rs, &pim->signals, listPointers, rs_tmp) {
        deactivateSignal(rs);
        LIST_REMOVE(rs, listPointers);
        UA_free(rs);
    }

    UA_String_clear(&es->name);
    UA_free(es);

#ifndef UA_HAVE_EPOLL
    singletonIM = NULL; /* Reset the global singleton pointer */
#endif

    return UA_STATUSCODE_GOOD;
}

UA_InterruptManager *
UA_InterruptManager_new_POSIX(const UA_String eventSourceName) {
#ifndef UA_HAVE_EPOLL
    /* There can be only one InterruptManager if epoll is not present */
    if(singletonIM)
        return NULL;
#endif

    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)
        UA_calloc(1, sizeof(UA_POSIXInterruptManager));
    if(!pim)
        return NULL;

#ifndef UA_HAVE_EPOLL
    singletonIM = pim; /* Register the singleton singleton pointer */
#endif

    UA_InterruptManager *im = &pim->im;
    im->eventSource.eventSourceType = UA_EVENTSOURCETYPE_INTERRUPTMANAGER;
    UA_String_copy(&eventSourceName, &im->eventSource.name);
    im->eventSource.start = startPOSIXInterruptManager;
    im->eventSource.stop = stopPOSIXInterruptManager;
    im->eventSource.free = freePOSIXInterruptmanager;
    im->registerInterrupt = registerPOSIXInterrupt;
    im->deregisterInterrupt = deregisterPOSIXInterrupt;
    return im;
}

#endif

/**** amalgamated original file "/plugins/ua_config_json.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Noel Graf)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */

#ifdef UA_ENABLE_ENCRYPTION
#endif

#define MAX_TOKENS 1024

typedef struct {
    const char *json;
    const cj5_token *tokens;
    size_t tokensSize;
    size_t index;
    UA_Byte depth;
    cj5_result result;

    UA_Logger *logging;
} ParsingCtx;

static UA_ByteString
getJsonPart(cj5_token tok, const char *json) {
    UA_ByteString bs;
    UA_ByteString_init(&bs);
    if(tok.type == CJ5_TOKEN_STRING) {
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
        bs.length = (tok.end - tok.start) + 3;
        return bs;
    } else {
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
        bs.length = (tok.end - tok.start) + 1;
        return bs;
    }
}

/* Forward declarations*/
#define PARSE_JSON(TYPE) static UA_StatusCode                   \
    TYPE##_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize)

typedef UA_StatusCode
(*parseJsonSignature)(ParsingCtx *ctx, void *configField, size_t *configFieldSize);

#ifdef UA_ENABLE_ENCRYPTION
static UA_ByteString
loadCertificateFile(const char *const path);
#endif

/* The DataType "kind" is an internal type classification. It is used to
 * dispatch handling to the correct routines. */
#define UA_SERVERCONFIGFIELDKINDS 25
typedef enum {
    /* Basic Types */
    UA_SERVERCONFIGFIELD_INT64 = 0,
    UA_SERVERCONFIGFIELD_UINT16,
    UA_SERVERCONFIGFIELD_UINT32,
    UA_SERVERCONFIGFIELD_UINT64,
    UA_SERVERCONFIGFIELD_STRING,
    UA_SERVERCONFIGFIELD_LOCALIZEDTEXT,
    UA_SERVERCONFIGFIELD_DOUBLE,
    UA_SERVERCONFIGFIELD_BOOLEAN,
    UA_SERVERCONFIGFIELD_DURATION,
    UA_SERVERCONFIGFIELD_DURATIONRANGE,
    UA_SERVERCONFIGFIELD_UINT32RANGE,

    /* Advanced Types */
    UA_SERVERCONFIGFIELD_BUILDINFO,
    UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION,
    UA_SERVERCONFIGFIELD_STRINGARRAY,
    UA_SERVERCONFIGFIELD_UINT32ARRAY,
    UA_SERVERCONFIGFIELD_DATETIME,
    UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION,
    UA_SERVERCONFIGFIELD_TCPCONFIGURATION,
    UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION,
    UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION,
    UA_SERVERCONFIGFIELD_MDNSCONFIGURATION,
    UA_SERVERCONFIGFIELD_SECURITYPOLICIES,
    UA_SERVERCONFIGFIELD_SECURITYPKI,

    /* Enumerations */
    UA_SERVERCONFIGFIELD_APPLICATIONTYPE,
    UA_SERVERCONFIGFIELD_RULEHANDLING
} UA_ServerConfigFieldKind;

extern const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS];

/*----------------------Basic Types------------------------*/
PARSE_JSON(Int64Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_Int64 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_INT64], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Int64 *field = (UA_Int64*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(UInt16Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_UInt16 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_UInt16 *field = (UA_UInt16*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(UInt32Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_UInt32 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_UInt32 *field = (UA_UInt32*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(UInt64Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_UInt64 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_UInt64 *field = (UA_UInt64*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(StringField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_String out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_String *field = (UA_String*)configField;
    if(field != NULL) {
        UA_String_clear(field);
        *field = out;
    }
    return retval;
}
PARSE_JSON(LocalizedTextField) {
    /*
     applicationName: {
        locale: "de-DE",
        text: "Test text"
    }
     */
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_String locale = {.length = 0, .data = NULL};
    UA_String text = {.length = 0, .data = NULL};
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &str_len);

            tok = ctx->tokens[++ctx->index];
            UA_ByteString buf = getJsonPart(tok, ctx->json);
            if(strcmp(field, "locale") == 0)
                retval |= UA_decodeJson(&buf, &locale, &UA_TYPES[UA_TYPES_STRING], NULL);
            else if(strcmp(field, "text") == 0)
                retval |= UA_decodeJson(&buf, &text, &UA_TYPES[UA_TYPES_STRING], NULL);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field);
            break;
        }
        default:
            break;
        }
    }
    UA_LocalizedText out;
    out.locale = locale;
    out.text = text;
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_LocalizedText *field = (UA_LocalizedText*)configField;
    if(field != NULL) {
        UA_LocalizedText_clear(field);
        *field = out;
    }
    return retval;
}
PARSE_JSON(DoubleField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_Double out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Double *field = (UA_Double *)configField;
    *field = out;
    return retval;
}
PARSE_JSON(BooleanField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_Boolean out;
    if(tok.type != CJ5_TOKEN_BOOL) {
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Value of type bool expected.");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }
    UA_String val = UA_STRING("true");
    if(UA_String_equal(&val, &buf)) {
        out = true;
    }else {
        out = false;
    }
    /* set server config field */
    UA_Boolean *field = (UA_Boolean *)configField;
    *field = out;
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(DurationField) {
    UA_Double double_value;
    UA_StatusCode retval = DoubleField_parseJson(ctx, &double_value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Duration *field = (UA_Duration*)configField;
    *field = (UA_Duration)double_value;
    return retval;
}
PARSE_JSON(DurationRangeField) {
    UA_DurationRange *field = (UA_DurationRange*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "min") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->min, NULL);
            else if(strcmp(field_str, "max") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->max, NULL);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(UInt32RangeField) {
    UA_UInt32Range *field = (UA_UInt32Range*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "min") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->min, NULL);
            else if(strcmp(field_str, "max") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->max, NULL);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}

/*----------------------Advanced Types------------------------*/
PARSE_JSON(BuildInfo) {
    UA_BuildInfo *field = (UA_BuildInfo*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "productUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
            else if(strcmp(field_str, "manufacturerName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->manufacturerName, NULL);
            else if(strcmp(field_str, "productName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productName, NULL);
            else if(strcmp(field_str, "softwareVersion") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->softwareVersion, NULL);
            else if(strcmp(field_str, "buildNumber") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->buildNumber, NULL);
            else if(strcmp(field_str, "buildDate") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DATETIME](ctx, &field->buildDate, NULL);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(ApplicationDescriptionField) {
    UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "applicationUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->applicationUri, NULL);
            else if(strcmp(field_str, "productUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
            else if(strcmp(field_str, "applicationName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_LOCALIZEDTEXT](ctx, &field->applicationName, NULL);
            else if(strcmp(field_str, "applicationType") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONTYPE](ctx, &field->applicationType, NULL);
            else if(strcmp(field_str, "gatewayServerUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->gatewayServerUri, NULL);
            else if(strcmp(field_str, "discoveryProfileUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->discoveryProfileUri, NULL);
            else if(strcmp(field_str, "discoveryUrls") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(StringArrayField) {
    if(configFieldSize == NULL) {
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
    size_t stringArraySize = 0;
    for(size_t j = tok.size; j > 0; j--) {
        UA_String out = {.length = 0, .data = NULL};
        parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
        UA_String_copy(&out, &stringArray[stringArraySize++]);
        UA_String_clear(&out);
    }
    /* Add to the config */
    UA_String **field = (UA_String**)configField;
    if(*configFieldSize > 0) {
        UA_Array_delete(*field, *configFieldSize,
                        &UA_TYPES[UA_TYPES_STRING]);
        *field = NULL;
        *configFieldSize = 0;
    }
    UA_StatusCode retval =
        UA_Array_copy(stringArray, stringArraySize,
                      (void**)field, &UA_TYPES[UA_TYPES_STRING]);
    *configFieldSize = stringArraySize;

    /* Clean up */
    UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
    return retval;
}
PARSE_JSON(UInt32ArrayField) {
    if(configFieldSize == NULL) {
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_UInt32 *numberArray = (UA_UInt32*)UA_malloc(sizeof(UA_UInt32) * tok.size);
    size_t numberArraySize = 0;
    for(size_t j = tok.size; j > 0; j--) {
        UA_UInt32 value;
        UA_StatusCode retval = UInt32Field_parseJson(ctx, &value, NULL);
        if(retval != UA_STATUSCODE_GOOD)
            continue;
        numberArray[numberArraySize++] = value;
    }
    /* Add to the config */
    UA_UInt32 **field = (UA_UInt32**)configField;
    if(*configFieldSize > 0) {
        UA_Array_delete(*field, *configFieldSize,
                        &UA_TYPES[UA_TYPES_UINT32]);
        *field = NULL;
        *configFieldSize = 0;
    }
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(numberArraySize > 0) {
        retval = UA_Array_copy(numberArray, numberArraySize,
                          (void **)field, &UA_TYPES[UA_TYPES_UINT32]);
        *configFieldSize = numberArraySize;
    }
    /* Clean up */
    UA_Array_delete(numberArray, numberArraySize, &UA_TYPES[UA_TYPES_UINT32]);
    return retval;
}
PARSE_JSON(DateTimeField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_DateTime out;
    UA_DateTime_init(&out);
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_DateTime *field = (UA_DateTime*)configField;
    *field = out;
    return retval;
}

PARSE_JSON(MdnsConfigurationField) {
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "mdnsServerName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsConfig.mdnsServerName, NULL);
            else if(strcmp(field_str, "serverCapabilities") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &config->mdnsConfig.serverCapabilities, &config->mdnsConfig.serverCapabilitiesSize);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD
            else if(strcmp(field_str, "mdnsInterfaceIP") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsInterfaceIP, NULL);
            /* mdnsIpAddressList and mdnsIpAddressListSize are only available if UA_HAS_GETIFADDR is not defined: */
# if !defined(UA_HAS_GETIFADDR)
            else if(strcmp(field_str, "mdnsIpAddressList") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32ARRAY](ctx, &config->mdnsIpAddressList, &config->mdnsIpAddressListSize);
# endif
#endif
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
        break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(SubscriptionConfigurationField) {
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "maxSubscriptions") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptions, NULL);
            else if(strcmp(field_str, "maxSubscriptionsPerSession") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptionsPerSession, NULL);
            else if(strcmp(field_str, "publishingIntervalLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->publishingIntervalLimits, NULL);
            else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->lifeTimeCountLimits, NULL);
            else if(strcmp(field_str, "keepAliveCountLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->keepAliveCountLimits, NULL);
            else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxNotificationsPerPublish, NULL);
            else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->enableRetransmissionQueue, NULL);
            else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxRetransmissionQueueSize, NULL);
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
            else if(strcmp(field_str, "maxEventsPerNode") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxEventsPerNode, NULL);
# endif
            else if(strcmp(field_str, "maxMonitoredItems") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItems, NULL);
            else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItemsPerSubscription, NULL);
            else if(strcmp(field_str, "samplingIntervalLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->samplingIntervalLimits, NULL);
            else if(strcmp(field_str, "queueSizeLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->queueSizeLimits, NULL);
            else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxPublishReqPerSession, NULL);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(TcpConfigurationField) {
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "tcpBufSize") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpBufSize, NULL);
            else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxMsgSize, NULL);
            else if(strcmp(field_str, "tcpMaxChunks") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxChunks, NULL);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(PubsubConfigurationField) {
#ifdef UA_ENABLE_PUBSUB
    UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "enableDeltaFrames") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableDeltaFrames, NULL);
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
            else if(strcmp(field_str, "enableInformationModelMethods") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableInformationModelMethods, NULL);
#endif
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(HistorizingConfigurationField) {
#ifdef UA_ENABLE_HISTORIZING
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "accessHistoryDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryDataCapability, NULL);
            else if(strcmp(field_str, "maxReturnDataValues") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnDataValues, NULL);
            else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryEventsCapability, NULL);
            else if(strcmp(field_str, "maxReturnEventValues") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnEventValues, NULL);
            else if(strcmp(field_str, "insertDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertDataCapability, NULL);
            else if(strcmp(field_str, "insertEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertEventCapability, NULL);
            else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertAnnotationsCapability, NULL);
            else if(strcmp(field_str, "replaceDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceDataCapability, NULL);
            else if(strcmp(field_str, "replaceEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceEventCapability, NULL);
            else if(strcmp(field_str, "updateDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateDataCapability, NULL);
            else if(strcmp(field_str, "updateEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateEventCapability, NULL);
            else if(strcmp(field_str, "deleteRawCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteRawCapability, NULL);
            else if(strcmp(field_str, "deleteEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteEventCapability, NULL);
            else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteAtTimeDataCapability, NULL);
            else {
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(SecurityPolciesField) {
#ifdef UA_ENABLE_ENCRYPTION
    UA_ServerConfig *config = (UA_ServerConfig*)configField;

    UA_String noneuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
    UA_String basic128Rsa15uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
    UA_String basic256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
    UA_String basic256Sha256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
    UA_String aes128sha256rsaoaepuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
    UA_String aes256sha256rsapssuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");

    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size; j > 0; j--) {

        UA_String policy = {.length = 0, .data = NULL};
        UA_ByteString certificate = {.length = 0, .data = NULL};
        UA_ByteString privateKey = {.length = 0, .data = NULL};

        tok = ctx->tokens[++ctx->index];
        for(size_t i = tok.size / 2; i > 0; i--) {
            tok = ctx->tokens[++ctx->index];
            switch(tok.type) {
            case CJ5_TOKEN_STRING: {
                char *field_str = (char *)UA_malloc(tok.size + 1);
                unsigned int str_len = 0;
                cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
                if(strcmp(field_str, "certificate") == 0) {
                    UA_String out = {.length = 0, .data = NULL};
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);

                    if(out.length > 0) {
                        char *certfile = (char *)UA_malloc(out.length + 1);
                        memcpy(certfile, out.data, out.length);
                        certfile[out.length] = '\0';
                        certificate = loadCertificateFile(certfile);
                        UA_String_clear(&out);
                        UA_free(certfile);
                    }
                } else if(strcmp(field_str, "privateKey") == 0) {
                    UA_String out = {.length = 0, .data = NULL};
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);

                    if(out.length > 0) {
                        char *keyfile = (char *)UA_malloc(out.length + 1);
                        memcpy(keyfile, out.data, out.length);
                        keyfile[out.length] = '\0';
                        privateKey = loadCertificateFile(keyfile);
                        UA_String_clear(&out);
                        UA_free(keyfile);
                    }
                } else if(strcmp(field_str, "policy") == 0) {
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &policy, NULL);
                } else {
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
                }
                UA_free(field_str);
                break;
            }
            default:
                break;
            }
        }

        if(certificate.length == 0 || privateKey.length == 0) {
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                           "Certificate and PrivateKey must be set for every policy.");
            if(policy.length > 0)
                UA_String_clear(&policy);
            if(certificate.length > 0)
                UA_ByteString_clear(&certificate);
            if(privateKey.length > 0)
                UA_ByteString_clear(&privateKey);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        UA_StatusCode retval = UA_STATUSCODE_GOOD;
        if(UA_String_equal(&policy, &noneuri)) {
            /* Nothing to do! */
        } else if(UA_String_equal(&policy, &basic128Rsa15uri)) {
            retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                               "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else if(UA_String_equal(&policy, &basic256uri)) {
            retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                               "Could not add SecurityPolicy#Basic256 with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else if(UA_String_equal(&policy, &basic256Sha256uri)) {
            retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                               "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else if(UA_String_equal(&policy, &aes128sha256rsaoaepuri)) {
            retval = UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                               "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else if(UA_String_equal(&policy, &aes256sha256rsapssuri)) {
             retval = UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(config, &certificate, &privateKey);
             if(retval != UA_STATUSCODE_GOOD) {
                 UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                                "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else {
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown Security Policy.");
        }

        /* Add all Endpoints */
        UA_ServerConfig_addAllEndpoints(config);

        if(policy.length > 0)
            UA_String_clear(&policy);
        if(certificate.length > 0)
            UA_ByteString_clear(&certificate);
        if(privateKey.length > 0)
            UA_ByteString_clear(&privateKey);
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(SecurityPkiField) {
#ifdef UA_ENABLE_ENCRYPTION
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    UA_String pkiFolder = {.length = 0, .data = NULL};

    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_StatusCode retval = UA_decodeJson(&buf, &pkiFolder, &UA_TYPES[UA_TYPES_STRING], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__)
    /* Set up the parameters for the filestore certificate store */
    UA_KeyValuePair params[2];
    size_t paramsSize = 2;

    params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
    params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
    UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);

    UA_KeyValueMap paramsMap;
    paramsMap.map = params;
    paramsMap.mapSize = paramsSize;

    /* set server config field */
    UA_NodeId defaultApplicationGroup =
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    retval = UA_CertificateGroup_Filestore(&config->secureChannelPKI, &defaultApplicationGroup,
                                           pkiFolder, config->logging, &paramsMap);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_String_clear(&pkiFolder);
        return retval;
    }

    UA_NodeId defaultUserTokenGroup =
            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
    retval = UA_CertificateGroup_Filestore(&config->sessionPKI, &defaultUserTokenGroup,
                                            pkiFolder, config->logging, &paramsMap);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_String_clear(&pkiFolder);
        return retval;
    }

    /* Clean up */
    UA_String_clear(&pkiFolder);
#else
    (void)config;
    UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                   "pkiFolder is not supported on this platform. "
                   "Trusted clients will not be verified.");
#endif
#else
    UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
                   "pkiFolder is set in the config but UA_ENABLE_ENCRYPTION "
                   "is not enabled. Trusted clients will not be verified.");
#endif
    return UA_STATUSCODE_GOOD;
}

/*----------------------Enumerations------------------------*/
PARSE_JSON(ApplicationTypeField) {
    UA_UInt32 enum_value;
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_ApplicationType *field = (UA_ApplicationType*)configField;
    *field = (UA_ApplicationType)enum_value;
    return retval;
}
PARSE_JSON(RuleHandlingField) {
    UA_UInt32 enum_value;
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_RuleHandling *field = (UA_RuleHandling*)configField;
    *field = (UA_RuleHandling)enum_value;
    return retval;
}

const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS] = {
    /* Basic Types */
    (parseJsonSignature)Int64Field_parseJson,
    (parseJsonSignature)UInt16Field_parseJson,
    (parseJsonSignature)UInt32Field_parseJson,
    (parseJsonSignature)UInt64Field_parseJson,
    (parseJsonSignature)StringField_parseJson,
    (parseJsonSignature)LocalizedTextField_parseJson,
    (parseJsonSignature)DoubleField_parseJson,
    (parseJsonSignature)BooleanField_parseJson,
    (parseJsonSignature)DurationField_parseJson,
    (parseJsonSignature)DurationRangeField_parseJson,
    (parseJsonSignature)UInt32RangeField_parseJson,

    /* Advanced Types */
    (parseJsonSignature)BuildInfo_parseJson,
    (parseJsonSignature)ApplicationDescriptionField_parseJson,
    (parseJsonSignature)StringArrayField_parseJson,
    (parseJsonSignature)UInt32ArrayField_parseJson,
    (parseJsonSignature)DateTimeField_parseJson,
    (parseJsonSignature)SubscriptionConfigurationField_parseJson,
    (parseJsonSignature)TcpConfigurationField_parseJson,
    (parseJsonSignature)PubsubConfigurationField_parseJson,
    (parseJsonSignature)HistorizingConfigurationField_parseJson,
    (parseJsonSignature)MdnsConfigurationField_parseJson,
    (parseJsonSignature)SecurityPolciesField_parseJson,
    (parseJsonSignature)SecurityPkiField_parseJson,

    /* Enumerations */
    (parseJsonSignature)ApplicationTypeField_parseJson,
    (parseJsonSignature)RuleHandlingField_parseJson,
};

/* Skips unknown item (simple, object or array) in config file. 
* Unknown items may happen if we don't support some features. 
* E.g. if  UA_ENABLE_ENCRYPTION is not defined and config file 
* contains "securityPolicies" entry.
*/
static void
skipUnknownItem(ParsingCtx* ctx) {
    unsigned int end = ctx->tokens[ctx->index].end;
    do {
        ctx->index++;
    } while (ctx->index < ctx->tokensSize &&
        ctx->tokens[ctx->index].start < end);
}

static UA_StatusCode
parseJSONConfig(UA_ServerConfig *config, UA_ByteString json_config) {
    // Parsing json config
    const char *json = (const char*)json_config.data;
    cj5_token tokens[MAX_TOKENS];
    cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);

    /* Validate the parse result: must succeed and produce a root object
     * with at least one key-value pair (i.e. >= 2 tokens). */
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
        return UA_STATUSCODE_BADDECODINGERROR;

    ParsingCtx ctx;
    ctx.json = json;
    ctx.result = r;
    ctx.tokens = r.tokens;
    ctx.tokensSize = r.num_tokens;
    ctx.index = 1; // The first token is ignored because it is known and not needed.

    ctx.logging = config->logging;

    /* Buffer for the field name */
    char field[256];

    size_t serverConfigSize = 0;
    if(ctx.tokens)
        serverConfigSize = (ctx.tokens[ctx.index-1].size/2);
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for (size_t j = serverConfigSize; j > 0; j--) {
        cj5_token tok = ctx.tokens[ctx.index];
        switch (tok.type) {
            case CJ5_TOKEN_STRING: {
                if(tok.size >= 255) {
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
                                   "Configuration field name too long");
                    continue;
                }
                unsigned int str_len = 0;
                cj5_error_code res = cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
                if(res != CJ5_ERROR_NONE) {
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
                                   "Configuration field name not a valid string");
                    continue;
                }
                if(strcmp(field, "buildInfo") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BUILDINFO](&ctx, &config->buildInfo, NULL);
                else if(strcmp(field, "applicationDescription") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION](&ctx, &config->applicationDescription, NULL);
                else if(strcmp(field, "shutdownDelay") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->shutdownDelay, NULL);
                else if(strcmp(field, "verifyRequestTimestamp") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->verifyRequestTimestamp, NULL);
                else if(strcmp(field, "allowEmptyVariables") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->allowEmptyVariables, NULL);
                else if(strcmp(field, "serverUrls") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](&ctx, &config->serverUrls, &config->serverUrlsSize);
                else if(strcmp(field, "tcpEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->tcpEnabled, NULL);
                else if(strcmp(field, "tcp") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_TCPCONFIGURATION](&ctx, config, NULL);
                else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
                else if(strcmp(field, "modellingRulesOnInstances") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->modellingRulesOnInstances, NULL);
                else if(strcmp(field, "maxSecureChannels") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSecureChannels, NULL);
                else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxSecurityTokenLifetime, NULL);
                else if(strcmp(field, "maxSessions") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSessions, NULL);
                else if(strcmp(field, "maxSessionTimeout") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->maxSessionTimeout, NULL);
                else if(strcmp(field, "maxNodesPerRead") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRead, NULL);
                else if(strcmp(field, "maxNodesPerWrite") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerWrite, NULL);
                else if(strcmp(field, "maxNodesPerMethodCall") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerMethodCall, NULL);
                else if(strcmp(field, "maxNodesPerBrowse") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerBrowse, NULL);
                else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRegisterNodes, NULL);
                else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
                else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerNodeManagement, NULL);
                else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxMonitoredItemsPerCall, NULL);
                else if(strcmp(field, "maxReferencesPerNode") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxReferencesPerNode, NULL);
                else if(strcmp(field, "reverseReconnectInterval") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->reverseReconnectInterval, NULL);

#if UA_MULTITHREADING >= 100
                else if(strcmp(field, "asyncOperationTimeout") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->asyncOperationTimeout, NULL);
                else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT64](&ctx, &config->maxAsyncOperationQueueSize, NULL);
#endif

#ifdef UA_ENABLE_DISCOVERY
                else if(strcmp(field, "discoveryCleanupTimeout") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->discoveryCleanupTimeout, NULL);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
                else if(strcmp(field, "mdnsEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->mdnsEnabled, NULL);
                else if(strcmp(field, "mdns") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_MDNSCONFIGURATION](&ctx, config, NULL);
#endif
#endif

#ifdef UA_ENABLE_SUBSCRIPTIONS
                else if(strcmp(field, "subscriptionsEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->subscriptionsEnabled, NULL);
                else if(strcmp(field, "subscriptions") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION](&ctx, config, NULL);
# endif

#ifdef UA_ENABLE_HISTORIZING
                else if(strcmp(field, "historizingEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->historizingEnabled, NULL);
                else if(strcmp(field, "historizing") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION](&ctx, config, NULL);
#endif

#ifdef UA_ENABLE_PUBSUB
                else if(strcmp(field, "pubsubEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->pubsubEnabled, NULL);
                else if(strcmp(field, "pubsub") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION](&ctx, &config->pubSubConfig, NULL);
#endif
#ifdef UA_ENABLE_ENCRYPTION
                else if(strcmp(field, "securityPolicies") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPOLICIES](&ctx, config, NULL);
                else if(strcmp(field, "pkiFolder") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPKI](&ctx, config, NULL);
#endif
                else {
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled.", field);
                    /* skip the name of item */
                    ++ctx.index;
                    /* skip value of unknown item */
                    skipUnknownItem(&ctx);
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
                       We must decrement index in oder following increment will
                       still set index to the right position (name of the following item) */
                    --ctx.index;
                }
                if(retval != UA_STATUSCODE_GOOD) {
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION,
                                 "An error occurred while parsing the configuration field %s", field);
                    return retval;
                }
                break;
            }
            default:
                break;
        }
        ctx.index += 1;
    }
    return retval;
}

UA_Server *
UA_Server_newFromFile(const UA_ByteString json_config) {
    UA_ServerConfig config;
    memset(&config, 0, sizeof(UA_ServerConfig));
    UA_StatusCode res = UA_ServerConfig_setDefault(&config);
    res |= parseJSONConfig(&config, json_config);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clear(&config);
        return NULL;
    }
    return UA_Server_newWithConfig(&config);
}

UA_StatusCode
UA_ServerConfig_updateFromFile(UA_ServerConfig *config, const UA_ByteString json_config) {
    UA_StatusCode res = parseJSONConfig(config, json_config);
    return res;
}

#ifdef UA_ENABLE_ENCRYPTION
static UA_ByteString
loadCertificateFile(const char *const path) {
    UA_ByteString fileContents = UA_BYTESTRING_NULL;

    /* Open the file */
    FILE *fp = fopen(path, "rb");
    if(!fp) {
        errno = 0; /* We read errno also from the tcp layer... */
        return fileContents;
    }

    /* Get the file length, allocate the data and read */
    if(fseek(fp, 0, SEEK_END) != 0) {
        fclose(fp);
        errno = 0;
        return fileContents;
    }

    long length = ftell(fp);
    if(length < 0) {
        fclose(fp);
        errno = 0;
        return fileContents;
    }

    fileContents.length = (size_t)length;
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
    if(fileContents.data) {
        if(fseek(fp, 0, SEEK_SET) != 0) {
            fclose(fp);
            UA_ByteString_clear(&fileContents);
            errno = 0;
            return fileContents;
        }
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
        if(read != fileContents.length)
            UA_ByteString_clear(&fileContents);
    } else {
        fileContents.length = 0;
    }
    fclose(fp);

    return fileContents;
}
#endif

/**** amalgamated original file "/plugins/historydata/ua_history_data_backend_memory.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
 *    Copyright 2021 (c) luibass92 <luibass92@live.it> (Author: Luigi Bassetta)
 */


#include <limits.h>
#include <string.h>

typedef struct {
    UA_DateTime timestamp;
    UA_DataValue value;
} UA_DataValueMemoryStoreItem;

static void
UA_DataValueMemoryStoreItem_clear(UA_DataValueMemoryStoreItem* item) {
    UA_DateTime_clear(&item->timestamp);
    UA_DataValue_clear(&item->value);
}

typedef struct {
    UA_NodeId nodeId;
    UA_DataValueMemoryStoreItem **dataStore;
    size_t storeEnd;
    size_t storeSize;
    /* New field useful for circular buffer management */
    size_t lastInserted;
} UA_NodeIdStoreContextItem_backend_memory;

static void
UA_NodeIdStoreContextItem_clear(UA_NodeIdStoreContextItem_backend_memory* item) {
    UA_NodeId_clear(&item->nodeId);
    for (size_t i = 0; i < item->storeEnd; ++i) {
        UA_DataValueMemoryStoreItem_clear(item->dataStore[i]);
        UA_free(item->dataStore[i]);
    }
    UA_free(item->dataStore);
}

typedef struct {
    UA_NodeIdStoreContextItem_backend_memory *dataStore;
    size_t storeEnd;
    size_t storeSize;
    size_t initialStoreSize;
} UA_MemoryStoreContext;

static void
UA_MemoryStoreContext_clear(UA_MemoryStoreContext* ctx) {
    for (size_t i = 0; i < ctx->storeEnd; ++i) {
        UA_NodeIdStoreContextItem_clear(&ctx->dataStore[i]);
    }
    UA_free(ctx->dataStore);
    memset(ctx, 0, sizeof(UA_MemoryStoreContext));
}

static UA_NodeIdStoreContextItem_backend_memory *
getNewNodeIdContext_backend_memory(UA_MemoryStoreContext* context,
                                   UA_Server *server,
                                   const UA_NodeId *nodeId) {
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext*)context;
    if (ctx->storeEnd >= ctx->storeSize) {
        size_t newStoreSize = ctx->storeSize * 2;
        if (newStoreSize == 0)
            return NULL;
        ctx->dataStore = (UA_NodeIdStoreContextItem_backend_memory*)UA_realloc(ctx->dataStore,  (newStoreSize * sizeof(UA_NodeIdStoreContextItem_backend_memory)));
        if (!ctx->dataStore) {
            ctx->storeSize = 0;
            return NULL;
        }
        ctx->storeSize = newStoreSize;
    }
    UA_NodeIdStoreContextItem_backend_memory *item = &ctx->dataStore[ctx->storeEnd];
    UA_NodeId_copy(nodeId, &item->nodeId);
    UA_DataValueMemoryStoreItem ** store = (UA_DataValueMemoryStoreItem **)UA_calloc(ctx->initialStoreSize, sizeof(UA_DataValueMemoryStoreItem*));
    if (!store) {
        UA_NodeIdStoreContextItem_clear(item);
        return NULL;
    }
    item->dataStore = store;
    item->storeSize = ctx->initialStoreSize;
    item->storeEnd = 0;
    ++ctx->storeEnd;
    return item;
}

static UA_NodeIdStoreContextItem_backend_memory *
getNodeIdStoreContextItem_backend_memory(UA_MemoryStoreContext* context,
                                         UA_Server *server,
                                         const UA_NodeId *nodeId)
{
    for (size_t i = 0; i < context->storeEnd; ++i) {
        if (UA_NodeId_equal(nodeId, &context->dataStore[i].nodeId)) {
            return &context->dataStore[i];
        }
    }
    return getNewNodeIdContext_backend_memory(context, server, nodeId);
}

static UA_Boolean
binarySearch_backend_memory(const UA_NodeIdStoreContextItem_backend_memory* item,
                            const UA_DateTime timestamp,
                            size_t *index) {
    if (item->storeEnd == 0) {
        *index = item->storeEnd;
        return false;
    }
    size_t min = 0;
    size_t max = item->storeEnd - 1;
    while (min <= max) {
        *index = (min + max) / 2;
        if (item->dataStore[*index]->timestamp == timestamp) {
            return true;
        } else if (item->dataStore[*index]->timestamp < timestamp) {
            if (*index == item->storeEnd - 1) {
                *index = item->storeEnd;
                return false;
            }
            min = *index + 1;
        } else {
            if (*index == 0)
                return false;
            max = *index - 1;
        }
    }
    *index = min;
    return false;

}

static size_t
resultSize_backend_memory(UA_Server *server,
                          void *context,
                          const UA_NodeId *sessionId,
                          void *sessionContext,
                          const UA_NodeId * nodeId,
                          size_t startIndex,
                          size_t endIndex) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    if (item->storeEnd == 0
            || startIndex == item->storeEnd
            || endIndex == item->storeEnd)
        return 0;
    return endIndex - startIndex + 1;
}

static size_t
getDateTimeMatch_backend_memory(UA_Server *server,
                                void *context,
                                const UA_NodeId *sessionId,
                                void *sessionContext,
                                const UA_NodeId * nodeId,
                                const UA_DateTime timestamp,
                                const MatchStrategy strategy) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    size_t current;
    UA_Boolean retval = binarySearch_backend_memory(item, timestamp, &current);

    if ((strategy == MATCH_EQUAL
         || strategy == MATCH_EQUAL_OR_AFTER
         || strategy == MATCH_EQUAL_OR_BEFORE)
            && retval)
        return current;
    switch (strategy) {
    case MATCH_AFTER:
        if (retval)
            return current+1;
        return current;
    case MATCH_EQUAL_OR_AFTER:
        return current;
    case MATCH_EQUAL_OR_BEFORE:
        // retval == true aka "equal" is handled before
        // Fall through if !retval
    case MATCH_BEFORE:
        if (current > 0)
            return current-1;
        else
            return item->storeEnd;
    default:
        break;
    }
    return item->storeEnd;
}


static UA_StatusCode
serverSetHistoryData_backend_memory(UA_Server *server,
                                    void *context,
                                    const UA_NodeId *sessionId,
                                    void *sessionContext,
                                    const UA_NodeId * nodeId,
                                    UA_Boolean historizing,
                                    const UA_DataValue *value)
{
    UA_NodeIdStoreContextItem_backend_memory *item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);

    if (item->storeEnd >= item->storeSize) {
        size_t newStoreSize = item->storeSize == 0 ? INITIAL_MEMORY_STORE_SIZE : item->storeSize * 2;
        item->dataStore = (UA_DataValueMemoryStoreItem **)UA_realloc(item->dataStore,  (newStoreSize * sizeof(UA_DataValueMemoryStoreItem*)));
        if (!item->dataStore) {
            item->storeSize = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        item->storeSize = newStoreSize;
    }
    UA_DateTime timestamp = 0;
    if (value->hasSourceTimestamp) {
        timestamp = value->sourceTimestamp;
    } else if (value->hasServerTimestamp) {
        timestamp = value->serverTimestamp;
    } else {
        timestamp = UA_DateTime_now();
    }
    UA_DataValueMemoryStoreItem *newItem = (UA_DataValueMemoryStoreItem *)UA_calloc(1, sizeof(UA_DataValueMemoryStoreItem));
    newItem->timestamp = timestamp;
    UA_DataValue_copy(value, &newItem->value);
    if(!newItem->value.hasServerTimestamp) {
        newItem->value.serverTimestamp = timestamp;
        newItem->value.hasServerTimestamp = true;
    }
    size_t index = getDateTimeMatch_backend_memory(server,
                                                   context,
                                                   NULL,
                                                   NULL,
                                                   nodeId,
                                                   timestamp,
                                                   MATCH_EQUAL_OR_AFTER);
    if (item->storeEnd > 0 && index < item->storeEnd) {
        memmove(&item->dataStore[index+1], &item->dataStore[index], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index));
    }
    item->dataStore[index] = newItem;
    ++item->storeEnd;
    return UA_STATUSCODE_GOOD;
}

static void
UA_MemoryStoreContext_delete(UA_MemoryStoreContext* ctx) {
    UA_MemoryStoreContext_clear(ctx);
    UA_free(ctx);
}

static size_t
getEnd_backend_memory(UA_Server *server,
                      void *context,
                      const UA_NodeId *sessionId,
                      void *sessionContext,
                      const UA_NodeId * nodeId) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    return item->storeEnd;
}

static size_t
lastIndex_backend_memory(UA_Server *server,
                         void *context,
                         const UA_NodeId *sessionId,
                         void *sessionContext,
                         const UA_NodeId * nodeId) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    if (item->storeEnd == 0)
        return 0;
    return item->storeEnd - 1;
}

static size_t
firstIndex_backend_memory(UA_Server *server,
                          void *context,
                          const UA_NodeId *sessionId,
                          void *sessionContext,
                          const UA_NodeId * nodeId) {
    return 0;
}

static UA_Boolean
boundSupported_backend_memory(UA_Server *server,
                              void *context,
                              const UA_NodeId *sessionId,
                              void *sessionContext,
                              const UA_NodeId * nodeId) {
    return true;
}

static UA_Boolean
timestampsToReturnSupported_backend_memory(UA_Server *server,
                                           void *context,
                                           const UA_NodeId *sessionId,
                                           void *sessionContext,
                                           const UA_NodeId *nodeId,
                                           const UA_TimestampsToReturn timestampsToReturn) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    if (item->storeEnd == 0) {
        return true;
    }
    if (timestampsToReturn == UA_TIMESTAMPSTORETURN_NEITHER
            || timestampsToReturn == UA_TIMESTAMPSTORETURN_INVALID
            || (timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER
                && !item->dataStore[0]->value.hasServerTimestamp)
            || (timestampsToReturn == UA_TIMESTAMPSTORETURN_SOURCE
                && !item->dataStore[0]->value.hasSourceTimestamp)
            || (timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH
                && !(item->dataStore[0]->value.hasSourceTimestamp
                     && item->dataStore[0]->value.hasServerTimestamp))) {
        return false;
    }
    return true;
}

static const UA_DataValue*
getDataValue_backend_memory(UA_Server *server,
                            void *context,
                            const UA_NodeId *sessionId,
                            void *sessionContext,
                            const UA_NodeId * nodeId, size_t index) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    return &item->dataStore[index]->value;
}

static UA_StatusCode
UA_DataValue_backend_copyRange(const UA_DataValue *src, UA_DataValue *dst,
                               const UA_NumericRange range)
{
    memcpy(dst, src, sizeof(UA_DataValue));
    if (src->hasValue)
        return UA_Variant_copyRange(&src->value, &dst->value, range);
    return UA_STATUSCODE_BADDATAUNAVAILABLE;
}

static UA_StatusCode
copyDataValues_backend_memory(UA_Server *server,
                              void *context,
                              const UA_NodeId *sessionId,
                              void *sessionContext,
                              const UA_NodeId * nodeId,
                              size_t startIndex,
                              size_t endIndex,
                              UA_Boolean reverse,
                              size_t maxValues,
                              UA_NumericRange range,
                              UA_Boolean releaseContinuationPoints,
                              const UA_ByteString *continuationPoint,
                              UA_ByteString *outContinuationPoint,
                              size_t * providedValues,
                              UA_DataValue * values)
{
    size_t skip = 0;
    if (continuationPoint->length > 0) {
        if (continuationPoint->length == sizeof(size_t)) {
            skip = *((size_t*)(continuationPoint->data));
        } else {
            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        }
    }
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    size_t index = startIndex;
    size_t counter = 0;
    size_t skipedValues = 0;
    if (reverse) {
        while (index >= endIndex && index < item->storeEnd && counter < maxValues) {
            if (skipedValues++ >= skip) {
                if (range.dimensionsSize > 0) {
                    UA_DataValue_backend_copyRange(&item->dataStore[index]->value, &values[counter], range);
                } else {
                    UA_DataValue_copy(&item->dataStore[index]->value, &values[counter]);
                }
                ++counter;
            }
            --index;
        }
    } else {
        while (index <= endIndex && counter < maxValues) {
            if (skipedValues++ >= skip) {
                if (range.dimensionsSize > 0) {
                    UA_DataValue_backend_copyRange(&item->dataStore[index]->value, &values[counter], range);
                } else {
                    UA_DataValue_copy(&item->dataStore[index]->value, &values[counter]);
                }
                ++counter;
            }
            ++index;
        }
    }

    if (providedValues)
        *providedValues = counter;

    if ((!reverse && (endIndex-startIndex-skip+1) > counter) || (reverse && (startIndex-endIndex-skip+1) > counter)) {
        outContinuationPoint->length = sizeof(size_t);
        size_t t = sizeof(size_t);
        outContinuationPoint->data = (UA_Byte*)UA_malloc(t);
        *((size_t*)(outContinuationPoint->data)) = skip + counter;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
insertDataValue_backend_memory(UA_Server *server,
                   void *hdbContext,
                   const UA_NodeId *sessionId,
                   void *sessionContext,
                   const UA_NodeId *nodeId,
                   const UA_DataValue *value)
{
    if (!value->hasSourceTimestamp && !value->hasServerTimestamp)
        return UA_STATUSCODE_BADINVALIDTIMESTAMP;
    const UA_DateTime timestamp = value->hasSourceTimestamp ? value->sourceTimestamp : value->serverTimestamp;
    UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)hdbContext, server, nodeId);

    size_t index = getDateTimeMatch_backend_memory(server,
                                    hdbContext,
                                    sessionId,
                                    sessionContext,
                                    nodeId,
                                    timestamp,
                                    MATCH_EQUAL_OR_AFTER);
    if (item->storeEnd != index && item->dataStore[index]->timestamp == timestamp)
        return UA_STATUSCODE_BADENTRYEXISTS;

    if (item->storeEnd >= item->storeSize) {
        size_t newStoreSize = item->storeSize == 0 ? INITIAL_MEMORY_STORE_SIZE : item->storeSize * 2;
        item->dataStore = (UA_DataValueMemoryStoreItem **)UA_realloc(item->dataStore,  (newStoreSize * sizeof(UA_DataValueMemoryStoreItem*)));
        if (!item->dataStore) {
            item->storeSize = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        item->storeSize = newStoreSize;
    }
    UA_DataValueMemoryStoreItem *newItem = (UA_DataValueMemoryStoreItem *)UA_calloc(1, sizeof(UA_DataValueMemoryStoreItem));
    newItem->timestamp = timestamp;
    UA_DataValue_copy(value, &newItem->value);
    if(!newItem->value.hasServerTimestamp) {
        newItem->value.serverTimestamp = timestamp;
        newItem->value.hasServerTimestamp = true;
    }

    if (item->storeEnd > 0 && index < item->storeEnd) {
        memmove(&item->dataStore[index+1], &item->dataStore[index], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index));
    }
    item->dataStore[index] = newItem;
    ++item->storeEnd;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
replaceDataValue_backend_memory(UA_Server *server,
                    void *hdbContext,
                    const UA_NodeId *sessionId,
                    void *sessionContext,
                    const UA_NodeId *nodeId,
                    const UA_DataValue *value)
{
    if (!value->hasSourceTimestamp && !value->hasServerTimestamp)
        return UA_STATUSCODE_BADINVALIDTIMESTAMP;
    const UA_DateTime timestamp = value->hasSourceTimestamp ? value->sourceTimestamp : value->serverTimestamp;
    UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)hdbContext, server, nodeId);

    size_t index = getDateTimeMatch_backend_memory(server,
                                    hdbContext,
                                    sessionId,
                                    sessionContext,
                                    nodeId,
                                    timestamp,
                                    MATCH_EQUAL);
    if (index == item->storeEnd)
        return UA_STATUSCODE_BADNOENTRYEXISTS;
    UA_DataValue_clear(&item->dataStore[index]->value);
    UA_DataValue_copy(value, &item->dataStore[index]->value);
    if(!item->dataStore[index]->value.hasServerTimestamp) {
        item->dataStore[index]->value.serverTimestamp = timestamp;
        item->dataStore[index]->value.hasServerTimestamp = true;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
updateDataValue_backend_memory(UA_Server *server,
                   void *hdbContext,
                   const UA_NodeId *sessionId,
                   void *sessionContext,
                   const UA_NodeId *nodeId,
                   const UA_DataValue *value)
{
    // we first try to replace, because it is cheap
    UA_StatusCode ret = replaceDataValue_backend_memory(server,
                                                        hdbContext,
                                                        sessionId,
                                                        sessionContext,
                                                        nodeId,
                                                        value);
    if (ret == UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_GOODENTRYREPLACED;

    ret = insertDataValue_backend_memory(server,
                                          hdbContext,
                                          sessionId,
                                          sessionContext,
                                          nodeId,
                                          value);
    if (ret == UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_GOODENTRYINSERTED;

    return ret;
}

static UA_StatusCode
removeDataValue_backend_memory(UA_Server *server,
                               void *hdbContext,
                               const UA_NodeId *sessionId,
                               void *sessionContext,
                               const UA_NodeId *nodeId,
                               UA_DateTime startTimestamp,
                               UA_DateTime endTimestamp)
{
    UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)hdbContext, server, nodeId);
    size_t storeEnd = item->storeEnd;
    // The first index which will be deleted
    size_t index1;
    // the first index which is not deleted
    size_t index2;
    if (startTimestamp > endTimestamp) {
        return UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED;
    }
    if (startTimestamp == endTimestamp) {
        index1 = getDateTimeMatch_backend_memory(server,
                                        hdbContext,
                                        sessionId,
                                        sessionContext,
                                        nodeId,
                                        startTimestamp,
                                        MATCH_EQUAL);
        if (index1 == storeEnd)
            return UA_STATUSCODE_BADNODATA;
        index2 = index1 + 1;
    } else {
        index1 = getDateTimeMatch_backend_memory(server,
                                        hdbContext,
                                        sessionId,
                                        sessionContext,
                                        nodeId,
                                        startTimestamp,
                                        MATCH_EQUAL_OR_AFTER);
        index2 = getDateTimeMatch_backend_memory(server,
                                        hdbContext,
                                        sessionId,
                                        sessionContext,
                                        nodeId,
                                        endTimestamp,
                                        MATCH_BEFORE);
        if (index2 == storeEnd || index1 == storeEnd || index1 > index2 )
            return UA_STATUSCODE_BADNODATA;
        ++index2;
    }
#ifndef __clang_analyzer__
    for (size_t i = index1; i < index2; ++i) {
        UA_DataValueMemoryStoreItem_clear(item->dataStore[i]);
        UA_free(item->dataStore[i]);
    }
    memmove(&item->dataStore[index1], &item->dataStore[index2], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index2));
    item->storeEnd -= index2 - index1;
#else
    (void)index1;
    (void)index2;
#endif
    return UA_STATUSCODE_GOOD;
}

static void
deleteMembers_backend_memory(UA_HistoryDataBackend *backend)
{
    if (backend == NULL || backend->context == NULL)
        return;
    UA_MemoryStoreContext_clear((UA_MemoryStoreContext*)backend->context);
    UA_free(backend->context);
}



UA_HistoryDataBackend
UA_HistoryDataBackend_Memory(size_t initialNodeIdStoreSize, size_t initialDataStoreSize) {
    if (initialNodeIdStoreSize == 0)
        initialNodeIdStoreSize = 1;
    if (initialDataStoreSize == 0)
        initialDataStoreSize = 1;
    UA_HistoryDataBackend result;
    memset(&result, 0, sizeof(UA_HistoryDataBackend));
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext *)UA_calloc(1, sizeof(UA_MemoryStoreContext));
    if (!ctx)
        return result;
    ctx->dataStore = (UA_NodeIdStoreContextItem_backend_memory*)UA_calloc(initialNodeIdStoreSize, sizeof(UA_NodeIdStoreContextItem_backend_memory));
    ctx->initialStoreSize = initialDataStoreSize;
    ctx->storeSize = initialNodeIdStoreSize;
    ctx->storeEnd = 0;
    result.serverSetHistoryData = &serverSetHistoryData_backend_memory;
    result.resultSize = &resultSize_backend_memory;
    result.getEnd = &getEnd_backend_memory;
    result.lastIndex = &lastIndex_backend_memory;
    result.firstIndex = &firstIndex_backend_memory;
    result.getDateTimeMatch = &getDateTimeMatch_backend_memory;
    result.copyDataValues = &copyDataValues_backend_memory;
    result.getDataValue = &getDataValue_backend_memory;
    result.boundSupported = &boundSupported_backend_memory;
    result.timestampsToReturnSupported = &timestampsToReturnSupported_backend_memory;
    result.insertDataValue =  &insertDataValue_backend_memory;
    result.updateDataValue =  &updateDataValue_backend_memory;
    result.replaceDataValue =  &replaceDataValue_backend_memory;
    result.removeDataValue =  &removeDataValue_backend_memory;
    result.deleteMembers = &deleteMembers_backend_memory;
    result.getHistoryData = NULL;
    result.context = ctx;
    return result;
}

void
UA_HistoryDataBackend_Memory_clear(UA_HistoryDataBackend *backend)
{
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext*)backend->context;
    UA_MemoryStoreContext_delete(ctx);
    memset(backend, 0, sizeof(UA_HistoryDataBackend));
}

/* Circular buffer implementation */

static UA_NodeIdStoreContextItem_backend_memory *
getNewNodeIdContext_backend_memory_Circular(UA_MemoryStoreContext *context,
                                            UA_Server *server,
                                            const UA_NodeId *nodeId) {
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext *)context;
    if(ctx->storeEnd >= ctx->storeSize) {
        return NULL;
    }
    UA_NodeIdStoreContextItem_backend_memory *item = &ctx->dataStore[ctx->storeEnd];
    UA_NodeId_copy(nodeId, &item->nodeId);
    UA_DataValueMemoryStoreItem **store = (UA_DataValueMemoryStoreItem **)UA_calloc(ctx->initialStoreSize, sizeof(UA_DataValueMemoryStoreItem *));
    if(!store) {
        UA_NodeIdStoreContextItem_clear(item);
        return NULL;
    }
    item->dataStore = store;
    item->storeSize = ctx->initialStoreSize;
    item->storeEnd = 0;
    ++ctx->storeEnd;
    return item;
}

static UA_NodeIdStoreContextItem_backend_memory *
getNodeIdStoreContextItem_backend_memory_Circular(UA_MemoryStoreContext *context,
                                                  UA_Server *server,
                                                  const UA_NodeId *nodeId) {
    for(size_t i = 0; i < context->storeEnd; ++i) {
        if(UA_NodeId_equal(nodeId, &context->dataStore[i].nodeId)) {
            return &context->dataStore[i];
        }
    }
    return getNewNodeIdContext_backend_memory_Circular(context, server, nodeId);
}

static UA_StatusCode
serverSetHistoryData_backend_memory_Circular(UA_Server *server,
                                             void *context,
                                             const UA_NodeId *sessionId,
                                             void *sessionContext,
                                             const UA_NodeId *nodeId,
                                             UA_Boolean historizing,
                                             const UA_DataValue *value) {
    UA_NodeIdStoreContextItem_backend_memory *item = getNodeIdStoreContextItem_backend_memory_Circular((UA_MemoryStoreContext *)context, server, nodeId);
    if(item == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    if(item->lastInserted >= item->storeSize) {
        /* If the buffer size is overcomed, push new elements from the start of the buffer */
        item->lastInserted = 0;
    }
    UA_DateTime timestamp = 0;
    if(value->hasSourceTimestamp) {
        timestamp = value->sourceTimestamp;
    } else if(value->hasServerTimestamp) {
        timestamp = value->serverTimestamp;
    } else {
        timestamp = UA_DateTime_now();
    }
    UA_DataValueMemoryStoreItem *newItem = (UA_DataValueMemoryStoreItem *)UA_calloc(1, sizeof(UA_DataValueMemoryStoreItem));
    newItem->timestamp = timestamp;
    UA_DataValue_copy(value, &newItem->value);
    if(!newItem->value.hasServerTimestamp) {
        newItem->value.serverTimestamp = timestamp;
        newItem->value.hasServerTimestamp = true;
    }


    /* This implementation does NOT sort values by timestamp */

    if(item->dataStore[item->lastInserted] != NULL) {
        UA_DataValueMemoryStoreItem_clear(item->dataStore[item->lastInserted]);
        UA_free(item->dataStore[item->lastInserted]);
    }
    item->dataStore[item->lastInserted] = newItem;
    ++item->lastInserted;

    if(item->storeEnd < item->storeSize) {
        ++item->storeEnd;
    }

    return UA_STATUSCODE_GOOD;
}

static size_t
getResultSize_service_Circular(const UA_HistoryDataBackend *backend, UA_Server *server,
                               const UA_NodeId *sessionId, void *sessionContext,
                               const UA_NodeId *nodeId, UA_DateTime start,
                               UA_DateTime end, UA_UInt32 numValuesPerNode,
                               UA_Boolean returnBounds, size_t *startIndex,
                               size_t *endIndex, UA_Boolean *addFirst,
                               UA_Boolean *addLast, UA_Boolean *reverse) {
    *startIndex = 0;
    *endIndex = backend->lastIndex(server, backend->context, sessionId, sessionContext, nodeId);
    *addFirst = false;
    *addLast = false;
    if(end == LLONG_MIN) {
        *reverse = false;
    } else if(start == LLONG_MIN) {
        *reverse = true;
    } else {
        *reverse = end < start;
    }

    size_t size = 0;
    const UA_NodeIdStoreContextItem_backend_memory *item = getNodeIdStoreContextItem_backend_memory_Circular((UA_MemoryStoreContext *)backend->context, server, nodeId);
    if(item == NULL) {
        size = 0;
    } else {
        size = item->storeEnd;
    }
    return size;
}

static UA_StatusCode
getHistoryData_service_Circular(UA_Server *server,
                                const UA_NodeId *sessionId,
                                void *sessionContext,
                                const UA_HistoryDataBackend *backend,
                                const UA_DateTime start,
                                const UA_DateTime end,
                                const UA_NodeId *nodeId,
                                size_t maxSize,
                                UA_UInt32 numValuesPerNode,
                                UA_Boolean returnBounds,
                                UA_TimestampsToReturn timestampsToReturn,
                                UA_NumericRange range,
                                UA_Boolean releaseContinuationPoints,
                                const UA_ByteString *continuationPoint,
                                UA_ByteString *outContinuationPoint,
                                UA_HistoryData *historyData) {
    size_t *resultSize = &historyData->dataValuesSize;
    UA_DataValue **result = &historyData->dataValues;
    size_t skip = 0;
    UA_ByteString backendContinuationPoint;
    UA_ByteString_init(&backendContinuationPoint);
    if(continuationPoint->length > 0) {
        if(continuationPoint->length < sizeof(size_t))
            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        skip = *((size_t *)(continuationPoint->data));
        backendContinuationPoint.length = continuationPoint->length - sizeof(size_t);
        backendContinuationPoint.data = continuationPoint->data + sizeof(size_t);
    }
    size_t storeEnd = backend->getEnd(server, backend->context, sessionId, sessionContext, nodeId);
    size_t startIndex;
    size_t endIndex;
    UA_Boolean addFirst;
    UA_Boolean addLast;
    UA_Boolean reverse;
    size_t _resultSize = getResultSize_service_Circular(backend,
                                                        server,
                                                        sessionId,
                                                        sessionContext,
                                                        nodeId,
                                                        start,
                                                        end,
                                                        numValuesPerNode == 0 ? 0 : numValuesPerNode + (UA_UInt32)skip,
                                                        returnBounds,
                                                        &startIndex,
                                                        &endIndex,
                                                        &addFirst,
                                                        &addLast,
                                                        &reverse);
    *resultSize = _resultSize - skip;
    if(*resultSize > maxSize) {
        *resultSize = maxSize;
    }
    UA_DataValue *outResult = (UA_DataValue *)UA_Array_new(*resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
    if(!outResult) {
        *resultSize = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    *result = outResult;
    size_t counter = 0;
    if(addFirst) {
        if(skip == 0) {
            outResult[counter].hasStatus = true;
            outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
            outResult[counter].hasSourceTimestamp = true;
            if(start == LLONG_MIN) {
                outResult[counter].sourceTimestamp = end;
            } else {
                outResult[counter].sourceTimestamp = start;
            }
            ++counter;
        }
    }
    UA_ByteString backendOutContinuationPoint;
    UA_ByteString_init(&backendOutContinuationPoint);
    if(endIndex != storeEnd && startIndex != storeEnd) {
        size_t retval = 0;
        size_t valueSize = *resultSize - counter;
        if(valueSize + skip > _resultSize - addFirst - addLast) {
            if(skip == 0) {
                valueSize = _resultSize - addFirst - addLast;
            } else {
                valueSize = _resultSize - skip - addLast;
            }
        }
        UA_StatusCode ret = UA_STATUSCODE_GOOD;
        if(valueSize > 0)
            ret = backend->copyDataValues(server,
                                          backend->context,
                                          sessionId,
                                          sessionContext,
                                          nodeId,
                                          startIndex,
                                          endIndex,
                                          reverse,
                                          valueSize,
                                          range,
                                          releaseContinuationPoints,
                                          &backendContinuationPoint,
                                          &backendOutContinuationPoint,
                                          &retval,
                                          &outResult[counter]);
        if(ret != UA_STATUSCODE_GOOD) {
            UA_Array_delete(outResult, *resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
            *result = NULL;
            *resultSize = 0;
            return ret;
        }
        counter += retval;
    }
    if(addLast && counter < *resultSize) {
        outResult[counter].hasStatus = true;
        outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
        outResult[counter].hasSourceTimestamp = true;
        if(start == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp - UA_DATETIME_SEC;
        } else if(end == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp + UA_DATETIME_SEC;
        } else {
            outResult[counter].sourceTimestamp = end;
        }
    }
    // there are more values
    if(skip + *resultSize < _resultSize
       // there are not more values for this request, but there are more values in
       // database
       || (backendOutContinuationPoint.length > 0 && numValuesPerNode != 0)
       // we deliver just one value which is a FIRST/LAST value
       || (skip == 0 && addFirst == true && *resultSize == 1)) {
        if(UA_ByteString_allocBuffer(outContinuationPoint, backendOutContinuationPoint.length + sizeof(size_t)) != UA_STATUSCODE_GOOD) {
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        *((size_t *)(outContinuationPoint->data)) = skip + *resultSize;
        if(backendOutContinuationPoint.length > 0)
            memcpy(outContinuationPoint->data + sizeof(size_t), backendOutContinuationPoint.data, backendOutContinuationPoint.length);
    }
    UA_ByteString_clear(&backendOutContinuationPoint);
    return UA_STATUSCODE_GOOD;
}

UA_HistoryDataBackend
UA_HistoryDataBackend_Memory_Circular(size_t initialNodeIdStoreSize, size_t initialDataStoreSize) {
    UA_HistoryDataBackend result = UA_HistoryDataBackend_Memory(initialNodeIdStoreSize, initialDataStoreSize);
    result.serverSetHistoryData = &serverSetHistoryData_backend_memory_Circular;
    result.getHistoryData = &getHistoryData_service_Circular;
    return result;
}

/**** amalgamated original file "/plugins/historydata/ua_history_data_gathering_default.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
 *    Copyright 2021 (c) luibass92 <luibass92@live.it> (Author: Luigi Bassetta)
 */


#include <string.h>

typedef struct {
    UA_NodeId nodeId;
    UA_HistorizingNodeIdSettings setting;
    UA_MonitoredItemCreateResult monitoredResult;
    UA_Boolean paused;
} UA_NodeIdStoreContextItem_gathering_default;

typedef struct {
    UA_NodeIdStoreContextItem_gathering_default *dataStore;
    size_t storeEnd;
    size_t storeSize;
} UA_NodeIdStoreContext;

static void
dataChangeCallback_gathering_default(UA_Server *server,
                                     UA_UInt32 monitoredItemId,
                                     void *monitoredItemContext,
                                     const UA_NodeId *nodeId,
                                     void *nodeContext,
                                     UA_UInt32 attributeId,
                                     const UA_DataValue *value)
{
    UA_NodeIdStoreContextItem_gathering_default *context = (UA_NodeIdStoreContextItem_gathering_default*)monitoredItemContext;
    context->setting.historizingBackend.serverSetHistoryData(server,
                                                             context->setting.historizingBackend.context,
                                                             NULL,
                                                             NULL,
                                                             nodeId,
                                                             UA_TRUE,
                                                             value);
}

static UA_NodeIdStoreContextItem_gathering_default*
getNodeIdStoreContextItem_gathering_default(UA_NodeIdStoreContext *context,
                                            const UA_NodeId *nodeId)
{
    for (size_t i = 0; i < context->storeEnd; ++i) {
        if (UA_NodeId_equal(&context->dataStore[i].nodeId, nodeId)) {
            return &context->dataStore[i];
        }
    }
    return NULL;
}

static UA_StatusCode
startPoll(UA_Server *server, UA_NodeIdStoreContextItem_gathering_default *item)
{
    UA_MonitoredItemCreateRequest monitorRequest =
            UA_MonitoredItemCreateRequest_default(item->nodeId);
    monitorRequest.requestedParameters.samplingInterval = (double)item->setting.pollingInterval;
    monitorRequest.monitoringMode = UA_MONITORINGMODE_REPORTING;
    item->monitoredResult =
            UA_Server_createDataChangeMonitoredItem(server,
                                                    UA_TIMESTAMPSTORETURN_BOTH,
                                                    monitorRequest,
                                                    item,
                                                    &dataChangeCallback_gathering_default);
    return item->monitoredResult.statusCode;
}

static UA_StatusCode
stopPoll(UA_Server *server, UA_NodeIdStoreContextItem_gathering_default *item)
{
    UA_StatusCode retval = UA_Server_deleteMonitoredItem(server, item->monitoredResult.monitoredItemId);
    UA_MonitoredItemCreateResult_init(&item->monitoredResult);
    return retval;
}

static UA_StatusCode
stopPoll_gathering_default(UA_Server *server,
                           void *context,
                           const UA_NodeId *nodeId)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }
    if (item->setting.historizingUpdateStrategy != UA_HISTORIZINGUPDATESTRATEGY_POLL)
        return UA_STATUSCODE_BADNODEIDINVALID;
    if (item->monitoredResult.monitoredItemId == 0)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    return stopPoll(server, item);
}

static UA_StatusCode
startPoll_gathering_default(UA_Server *server,
                            void *context,
                            const UA_NodeId *nodeId)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }
    if (item->setting.historizingUpdateStrategy != UA_HISTORIZINGUPDATESTRATEGY_POLL)
        return UA_STATUSCODE_BADNODEIDINVALID;
    if (item->monitoredResult.monitoredItemId > 0)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    return startPoll(server, item);
}

static UA_StatusCode
registerNodeId_gathering_default(UA_Server *server,
                                 void *context,
                                 const UA_NodeId *nodeId,
                                 const UA_HistorizingNodeIdSettings setting)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    if (getNodeIdStoreContextItem_gathering_default(ctx, nodeId)) {
        return UA_STATUSCODE_BADNODEIDEXISTS;
    }
    if (ctx->storeEnd >= ctx->storeSize) {
        size_t newStoreSize = ctx->storeSize * 2;
        ctx->dataStore = (UA_NodeIdStoreContextItem_gathering_default*)UA_realloc(ctx->dataStore,  (newStoreSize * sizeof(UA_NodeIdStoreContextItem_gathering_default)));
        if (!ctx->dataStore) {
            ctx->storeSize = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        memset(&ctx->dataStore[ctx->storeSize], 0, (newStoreSize - ctx->storeSize) * sizeof(UA_NodeIdStoreContextItem_gathering_default));
        ctx->storeSize = newStoreSize;
    }
    UA_NodeId_copy(nodeId, &ctx->dataStore[ctx->storeEnd].nodeId);
    size_t current = ctx->storeEnd;
    ctx->dataStore[current].setting = setting;
    ++ctx->storeEnd;
    return UA_STATUSCODE_GOOD;
}

static const UA_HistorizingNodeIdSettings*
getHistorizingSetting_gathering_default(UA_Server *server,
                                        void *context,
                                        const UA_NodeId *nodeId)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (item) {
        return &item->setting;
    }
    return NULL;
}

static void
deleteMembers_gathering_default(UA_HistoryDataGathering *gathering)
{
    if (gathering == NULL || gathering->context == NULL)
        return;
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)gathering->context;
    for (size_t i = 0; i < ctx->storeEnd; ++i) {
        UA_NodeId_clear(&ctx->dataStore[i].nodeId);
        // There is still a monitored item present for this gathering
        // You need to remove it with UA_Server_deleteMonitoredItem
        UA_assert(ctx->dataStore[i].monitoredResult.monitoredItemId == 0);
    }
    UA_free(ctx->dataStore);
    UA_free(gathering->context);
}

static UA_Boolean
updateNodeIdSetting_gathering_default(UA_Server *server,
                                      void *context,
                                      const UA_NodeId *nodeId,
                                      const UA_HistorizingNodeIdSettings setting)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return false;
    }
    stopPoll_gathering_default(server, context, nodeId);
    item->setting = setting;
    return true;
}

static void
setValue_gathering_default(UA_Server *server,
                           void *context,
                           const UA_NodeId *sessionId,
                           void *sessionContext,
                           const UA_NodeId *nodeId,
                           UA_Boolean historizing,
                           const UA_DataValue *value)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return;
    }
    if(item->paused)
        return;
    if (item->setting.historizingUpdateStrategy == UA_HISTORIZINGUPDATESTRATEGY_VALUESET) {
        item->setting.historizingBackend.serverSetHistoryData(server,
                                                              item->setting.historizingBackend.context,
                                                              sessionId,
                                                              sessionContext,
                                                              nodeId,
                                                              historizing,
                                                              value);
    }
}

UA_HistoryDataGathering
UA_HistoryDataGathering_Default(size_t initialNodeIdStoreSize)
{
    UA_HistoryDataGathering gathering;
    memset(&gathering, 0, sizeof(UA_HistoryDataGathering));
    gathering.setValue = &setValue_gathering_default;
    gathering.getHistorizingSetting = &getHistorizingSetting_gathering_default;
    gathering.registerNodeId = &registerNodeId_gathering_default;
    gathering.startPoll = &startPoll_gathering_default;
    gathering.stopPoll = &stopPoll_gathering_default;
    gathering.deleteMembers = &deleteMembers_gathering_default;
    gathering.updateNodeIdSetting = &updateNodeIdSetting_gathering_default;
    UA_NodeIdStoreContext *context = (UA_NodeIdStoreContext*)UA_calloc(1, sizeof(UA_NodeIdStoreContext));
    context->storeEnd = 0;
    context->storeSize = initialNodeIdStoreSize;
    context->dataStore = (UA_NodeIdStoreContextItem_gathering_default*)UA_calloc(initialNodeIdStoreSize, sizeof(UA_NodeIdStoreContextItem_gathering_default));
    gathering.context = context;
    return gathering;
}

/* Circular buffer implementation */

static UA_StatusCode
registerNodeId_gathering_circular(UA_Server *server, void *context,
                                  const UA_NodeId *nodeId,
                                  const UA_HistorizingNodeIdSettings setting) {
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
    if(getNodeIdStoreContextItem_gathering_default(ctx, nodeId)) {
        return UA_STATUSCODE_BADNODEIDEXISTS;
    }
    if(ctx->storeEnd >= ctx->storeSize || !ctx->dataStore) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    UA_NodeId_copy(nodeId, &ctx->dataStore[ctx->storeEnd].nodeId);
    size_t current = ctx->storeEnd;
    ctx->dataStore[current].setting = setting;
    ++ctx->storeEnd;
    return UA_STATUSCODE_GOOD;
}

UA_HistoryDataGathering
UA_HistoryDataGathering_Circular(size_t initialNodeIdStoreSize) {
    UA_HistoryDataGathering gathering = UA_HistoryDataGathering_Default(initialNodeIdStoreSize);
    gathering.registerNodeId = &registerNodeId_gathering_circular;
    return gathering;
}

void gathering_default_pauseRecording(UA_HistoryDataGathering *gathering, const UA_NodeId *nodeId, UA_Boolean pause) {
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)gathering->context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if(item)
        item->paused = pause;
}


/**** amalgamated original file "/plugins/historydata/ua_history_database_default.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
 */


#include <limits.h>

typedef struct {
    UA_HistoryDataGathering gathering;
} UA_HistoryDatabaseContext_default;

static size_t
getResultSize_service_default(const UA_HistoryDataBackend* backend,
                              UA_Server *server,
                              const UA_NodeId *sessionId,
                              void* sessionContext,
                              const UA_NodeId *nodeId,
                              UA_DateTime start,
                              UA_DateTime end,
                              UA_UInt32 numValuesPerNode,
                              UA_Boolean returnBounds,
                              size_t *startIndex,
                              size_t *endIndex,
                              UA_Boolean *addFirst,
                              UA_Boolean *addLast,
                              UA_Boolean *reverse)
{
    size_t storeEnd = backend->getEnd(server, backend->context, sessionId, sessionContext, nodeId);
    size_t firstIndex = backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId);
    size_t lastIndex = backend->lastIndex(server, backend->context, sessionId, sessionContext, nodeId);
    *startIndex = storeEnd;
    *endIndex = storeEnd;
    *addFirst = false;
    *addLast = false;
    if (end == LLONG_MIN) {
        *reverse = false;
    } else if (start == LLONG_MIN) {
        *reverse = true;
    } else {
        *reverse = end < start;
    }
    UA_Boolean equal = start == end;
    size_t size = 0;
    if (lastIndex != storeEnd) {
        if (equal) {
            if (returnBounds) {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                if (*startIndex == storeEnd) {
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                    *addFirst = true;
                }
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *startIndex, *endIndex);
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL);
                *endIndex = *startIndex;
                if (*startIndex == storeEnd)
                    size = 0;
                else
                    size = 1;
            }
        } else if (start == LLONG_MIN) {
            *endIndex = firstIndex;
            if (returnBounds) {
                *addLast = true;
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_AFTER);
                if (*startIndex == storeEnd) {
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_BEFORE);
                    *addFirst = true;
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_BEFORE);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *endIndex, *startIndex);
        } else if (end == LLONG_MIN) {
            *endIndex = lastIndex;
            if (returnBounds) {
                *addLast = true;
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                if (*startIndex == storeEnd) {
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                    *addFirst = true;
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_AFTER);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *startIndex, *endIndex);
        } else if (*reverse) {
            if (returnBounds) {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_AFTER);
                if (*startIndex == storeEnd) {
                    *addFirst = true;
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_BEFORE);
                }
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_BEFORE);
                if (*endIndex == storeEnd) {
                    *addLast = true;
                    *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_AFTER);
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_AFTER);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *endIndex, *startIndex);
        } else {
            if (returnBounds) {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                if (*startIndex == storeEnd) {
                    *addFirst = true;
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                }
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_AFTER);
                if (*endIndex == storeEnd) {
                    *addLast = true;
                    *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_BEFORE);
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_AFTER);
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_BEFORE);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *startIndex, *endIndex);
        }
    } else if (returnBounds) {
        *addLast = true;
        *addFirst = true;
    }

    if (*addLast)
        ++size;
    if (*addFirst)
        ++size;

    if (numValuesPerNode > 0 && size > numValuesPerNode) {
        size = numValuesPerNode;
        *addLast = false;
    }
    return size;
}

static UA_StatusCode
getHistoryData_service_default(const UA_HistoryDataBackend* backend,
                               const UA_DateTime start,
                               const UA_DateTime end,
                               UA_Server *server,
                               const UA_NodeId *sessionId,
                               void *sessionContext,
                               const UA_NodeId* nodeId,
                               size_t maxSize,
                               UA_UInt32 numValuesPerNode,
                               UA_Boolean returnBounds,
                               UA_TimestampsToReturn timestampsToReturn,
                               UA_NumericRange range,
                               UA_Boolean releaseContinuationPoints,
                               const UA_ByteString *continuationPoint,
                               UA_ByteString *outContinuationPoint,
                               size_t *resultSize,
                               UA_DataValue ** result)
{
    size_t skip = 0;
    UA_ByteString backendContinuationPoint;
    UA_ByteString_init(&backendContinuationPoint);
    if (continuationPoint->length > 0) {
        if (continuationPoint->length >= sizeof(size_t)) {
            skip = *((size_t*)(continuationPoint->data));
            if (continuationPoint->length > 0) {
                backendContinuationPoint.length = continuationPoint->length - sizeof(size_t);
                backendContinuationPoint.data = continuationPoint->data + sizeof(size_t);
            }
        } else {
            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        }
    }

    size_t storeEnd = backend->getEnd(server, backend->context, sessionId, sessionContext, nodeId);
    size_t startIndex;
    size_t endIndex;
    UA_Boolean addFirst;
    UA_Boolean addLast;
    UA_Boolean reverse;
    size_t _resultSize = getResultSize_service_default(backend,
                                                       server,
                                                       sessionId,
                                                       sessionContext,
                                                       nodeId,
                                                       start,
                                                       end,
                                                       numValuesPerNode == 0 ? 0 : numValuesPerNode + (UA_UInt32)skip,
                                                       returnBounds,
                                                       &startIndex,
                                                       &endIndex,
                                                       &addFirst,
                                                       &addLast,
                                                       &reverse);
    *resultSize = _resultSize - skip;
    if (*resultSize > maxSize) {
        *resultSize = maxSize;
    }
    UA_DataValue *outResult= (UA_DataValue*)UA_Array_new(*resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
    if (!outResult) {
        *resultSize = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    *result = outResult;

    size_t counter = 0;
    if (addFirst) {
        if (skip == 0) {
            outResult[counter].hasStatus = true;
            outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
            outResult[counter].hasSourceTimestamp = true;
            if (start == LLONG_MIN) {
                outResult[counter].sourceTimestamp = end;
            } else {
                outResult[counter].sourceTimestamp = start;
            }
            ++counter;
        }
    }
    UA_ByteString backendOutContinuationPoint;
    UA_ByteString_init(&backendOutContinuationPoint);
    if (endIndex != storeEnd && startIndex != storeEnd) {
        size_t retval = 0;

        size_t valueSize = *resultSize - counter;
        if (valueSize + skip > _resultSize - addFirst - addLast) {
            if (skip == 0) {
                valueSize = _resultSize - addFirst - addLast;
            } else {
                valueSize = _resultSize - skip - addLast;
            }

        }

        UA_StatusCode ret = UA_STATUSCODE_GOOD;
        if (valueSize > 0)
            ret = backend->copyDataValues(server,
                                          backend->context,
                                          sessionId,
                                          sessionContext,
                                          nodeId,
                                          startIndex,
                                          endIndex,
                                          reverse,
                                          valueSize,
                                          range,
                                          releaseContinuationPoints,
                                          &backendContinuationPoint,
                                          &backendOutContinuationPoint,
                                          &retval,
                                          &outResult[counter]);
        if (ret != UA_STATUSCODE_GOOD) {
            UA_Array_delete(outResult, *resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
            *result = NULL;
            *resultSize = 0;
            return ret;
        }
        counter += retval;
    }
    if (addLast && counter < *resultSize) {
        outResult[counter].hasStatus = true;
        outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
        outResult[counter].hasSourceTimestamp = true;
        if (start == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp - UA_DATETIME_SEC;
        } else if (end == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp + UA_DATETIME_SEC;
        } else {
            outResult[counter].sourceTimestamp = end;
        }
    }
    // there are more values
    if (skip + *resultSize < _resultSize
            // there are not more values for this request, but there are more values in database
            || (backendOutContinuationPoint.length > 0
                && numValuesPerNode != 0)
            // we deliver just one value which is a FIRST/LAST value
            || (skip == 0
                && addFirst == true
                && *resultSize == 1)) {
        if(UA_ByteString_allocBuffer(outContinuationPoint, backendOutContinuationPoint.length + sizeof(size_t))
                != UA_STATUSCODE_GOOD) {
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        *((size_t*)(outContinuationPoint->data)) = skip + *resultSize;
        if(backendOutContinuationPoint.length > 0)
            memcpy(outContinuationPoint->data + sizeof(size_t), backendOutContinuationPoint.data, backendOutContinuationPoint.length);
    }
    UA_ByteString_clear(&backendOutContinuationPoint);
    return UA_STATUSCODE_GOOD;
}

static void
updateData_service_default(UA_Server *server,
                           void *hdbContext,
                           const UA_NodeId *sessionId,
                           void *sessionContext,
                           const UA_RequestHeader *requestHeader,
                           const UA_UpdateDataDetails *details,
                           UA_HistoryUpdateResult *result)
{
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)hdbContext;
    UA_Byte accessLevel = 0;
    UA_Server_readAccessLevel(server,
                              details->nodeId,
                              &accessLevel);
    if (!(accessLevel & UA_ACCESSLEVELMASK_HISTORYWRITE)) {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    UA_Boolean historizing = false;
    UA_Server_readHistorizing(server,
                              details->nodeId,
                              &historizing);
    if (!historizing) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }
    const UA_HistorizingNodeIdSettings *setting = ctx->gathering.getHistorizingSetting(
                server,
                ctx->gathering.context,
                &details->nodeId);

    if (!setting) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }

    UA_ServerConfig *config = UA_Server_getConfig(server);
    result->operationResultsSize = details->updateValuesSize;
    result->operationResults = (UA_StatusCode*)UA_Array_new(result->operationResultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
    for (size_t i = 0; i < details->updateValuesSize; ++i) {
        if (config->accessControl.allowHistoryUpdateUpdateData &&
            !config->accessControl.allowHistoryUpdateUpdateData(server, &config->accessControl, sessionId, sessionContext,
                                                                &details->nodeId, details->performInsertReplace,
                                                                &details->updateValues[i])) {
            result->operationResults[i] = UA_STATUSCODE_BADUSERACCESSDENIED;
            continue;
        }
        switch (details->performInsertReplace) {
        case UA_PERFORMUPDATETYPE_INSERT:
            if (!setting->historizingBackend.insertDataValue) {
                result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
                continue;
            }
            result->operationResults[i]
                    = setting->historizingBackend.insertDataValue(server,
                                                                  setting->historizingBackend.context,
                                                                  sessionId,
                                                                  sessionContext,
                                                                  &details->nodeId,
                                                                  &details->updateValues[i]);
            continue;
        case UA_PERFORMUPDATETYPE_REPLACE:
            if (!setting->historizingBackend.replaceDataValue) {
                result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
                continue;
            }
            result->operationResults[i]
                    = setting->historizingBackend.replaceDataValue(server,
                                                                   setting->historizingBackend.context,
                                                                   sessionId,
                                                                   sessionContext,
                                                                   &details->nodeId,
                                                                   &details->updateValues[i]);
            continue;
        case UA_PERFORMUPDATETYPE_UPDATE:
            if (!setting->historizingBackend.updateDataValue) {
                result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
                continue;
            }
            result->operationResults[i]
                    = setting->historizingBackend.updateDataValue(server,
                                                                  setting->historizingBackend.context,
                                                                  sessionId,
                                                                  sessionContext,
                                                                  &details->nodeId,
                                                                  &details->updateValues[i]);
            continue;
        default:
            result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
            continue;
        }
    }
}


static void
deleteRawModified_service_default(UA_Server *server,
                                  void *hdbContext,
                                  const UA_NodeId *sessionId,
                                  void *sessionContext,
                                  const UA_RequestHeader *requestHeader,
                                  const UA_DeleteRawModifiedDetails *details,
                                  UA_HistoryUpdateResult *result)
{
    if (details->isDeleteModified) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
        return;
    }
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)hdbContext;
    UA_Byte accessLevel = 0;
    UA_Server_readAccessLevel(server,
                              details->nodeId,
                              &accessLevel);
    if (!(accessLevel & UA_ACCESSLEVELMASK_HISTORYWRITE)) {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    UA_Boolean historizing = false;
    UA_Server_readHistorizing(server,
                              details->nodeId,
                              &historizing);
    if (!historizing) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }
    const UA_HistorizingNodeIdSettings *setting = ctx->gathering.getHistorizingSetting(
                server,
                ctx->gathering.context,
                &details->nodeId);

    if (!setting) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }
    if (!setting->historizingBackend.removeDataValue) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
        return;
    }

    UA_ServerConfig *config = UA_Server_getConfig(server);
    if (config->accessControl.allowHistoryUpdateDeleteRawModified &&
        !config->accessControl.allowHistoryUpdateDeleteRawModified(server,
                 &config->accessControl, sessionId, sessionContext, &details->nodeId,
                 details->startTime, details->endTime, details->isDeleteModified)) {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    result->statusCode
            = setting->historizingBackend.removeDataValue(server,
                                                          setting->historizingBackend.context,
                                                          sessionId,
                                                          sessionContext,
                                                          &details->nodeId,
                                                          details->startTime,
                                                          details->endTime);
}

static void
readRaw_service_default(UA_Server *server,
                        void *context,
                        const UA_NodeId *sessionId,
                        void *sessionContext,
                        const UA_RequestHeader *requestHeader,
                        const UA_ReadRawModifiedDetails *historyReadDetails,
                        UA_TimestampsToReturn timestampsToReturn,
                        UA_Boolean releaseContinuationPoints,
                        size_t nodesToReadSize,
                        const UA_HistoryReadValueId *nodesToRead,
                        UA_HistoryReadResponse *response,
                        UA_HistoryData * const * const historyData)
{
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)context;
    for (size_t i = 0; i < nodesToReadSize; ++i) {
        UA_Byte accessLevel = 0;
        UA_Server_readAccessLevel(server,
                                  nodesToRead[i].nodeId,
                                  &accessLevel);
        if (!(accessLevel & UA_ACCESSLEVELMASK_HISTORYREAD)) {
            response->results[i].statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
            continue;
        }

        UA_Boolean historizing = false;
        UA_Server_readHistorizing(server,
                                  nodesToRead[i].nodeId,
                                  &historizing);
        if (!historizing) {
            response->results[i].statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
            continue;
        }

        const UA_HistorizingNodeIdSettings *setting = ctx->gathering.getHistorizingSetting(
                    server,
                    ctx->gathering.context,
                    &nodesToRead[i].nodeId);

        if (!setting) {
            response->results[i].statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
            continue;
        }

        if (historyReadDetails->returnBounds && !setting->historizingBackend.boundSupported(
                    server,
                    setting->historizingBackend.context,
                    sessionId,
                    sessionContext,
                    &nodesToRead[i].nodeId)) {
            response->results[i].statusCode = UA_STATUSCODE_BADBOUNDNOTSUPPORTED;
            continue;
        }

        if (!setting->historizingBackend.timestampsToReturnSupported(
                    server,
                    setting->historizingBackend.context,
                    sessionId,
                    sessionContext,
                    &nodesToRead[i].nodeId,
                    timestampsToReturn)) {
            response->results[i].statusCode = UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED;
            continue;
        }

        UA_NumericRange range;
        range.dimensionsSize = 0;
        range.dimensions = NULL;
        if (nodesToRead[i].indexRange.length > 0) {
            UA_StatusCode rangeParseResult = UA_NumericRange_parse(&range, nodesToRead[i].indexRange);
            if (rangeParseResult != UA_STATUSCODE_GOOD) {
                response->results[i].statusCode = rangeParseResult;
                continue;
            }
        }

        UA_StatusCode getHistoryDataStatusCode;
        if (setting->historizingBackend.getHistoryData) {
            getHistoryDataStatusCode = setting->historizingBackend.getHistoryData(
                        server,
                        sessionId,
                        sessionContext,
                        &setting->historizingBackend,
                        historyReadDetails->startTime,
                        historyReadDetails->endTime,
                        &nodesToRead[i].nodeId,
                        setting->maxHistoryDataResponseSize,
                        historyReadDetails->numValuesPerNode,
                        historyReadDetails->returnBounds,
                        timestampsToReturn,
                        range,
                        releaseContinuationPoints,
                        &nodesToRead[i].continuationPoint,
                        &response->results[i].continuationPoint,
                        historyData[i]);
        } else {
            getHistoryDataStatusCode = getHistoryData_service_default(
                        &setting->historizingBackend,
                        historyReadDetails->startTime,
                        historyReadDetails->endTime,
                        server,
                        sessionId,
                        sessionContext,
                        &nodesToRead[i].nodeId,
                        setting->maxHistoryDataResponseSize,
                        historyReadDetails->numValuesPerNode,
                        historyReadDetails->returnBounds,
                        timestampsToReturn,
                        range,
                        releaseContinuationPoints,
                        &nodesToRead[i].continuationPoint,
                        &response->results[i].continuationPoint,
                        &historyData[i]->dataValuesSize,
                        &historyData[i]->dataValues);
        }
        if (getHistoryDataStatusCode != UA_STATUSCODE_GOOD) {
            response->results[i].statusCode = getHistoryDataStatusCode;
            continue;
        }
    }
    response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
    return;
}

static void
setValue_service_default(UA_Server *server,
                         void *context,
                         const UA_NodeId *sessionId,
                         void *sessionContext,
                         const UA_NodeId *nodeId,
                         UA_Boolean historizing,
                         const UA_DataValue *value)
{
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)context;
    if (ctx->gathering.setValue)
        ctx->gathering.setValue(server,
                                ctx->gathering.context,
                                sessionId,
                                sessionContext,
                                nodeId,
                                historizing,
                                value);
}

static void
clear_service_default(UA_HistoryDatabase *hdb)
{
    if (hdb == NULL || hdb->context == NULL)
        return;
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)hdb->context;
    ctx->gathering.deleteMembers(&ctx->gathering);
    UA_free(ctx);
}

UA_HistoryDatabase
UA_HistoryDatabase_default(UA_HistoryDataGathering gathering)
{
    UA_HistoryDatabase hdb;
    memset(&hdb, 0, sizeof(UA_HistoryDatabase));
    UA_HistoryDatabaseContext_default *context =
            (UA_HistoryDatabaseContext_default*)
            UA_calloc(1, sizeof(UA_HistoryDatabaseContext_default));
    context->gathering = gathering;
    hdb.context = context;
    hdb.readRaw = &readRaw_service_default;
    hdb.setValue = &setValue_service_default;
    hdb.updateData = &updateData_service_default;
    hdb.deleteRawModified = &deleteRawModified_service_default;
    hdb.clear = clear_service_default;
    return hdb;
}

/**** amalgamated original file "/plugins/ua_log_syslog.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#if defined(__linux__) || defined(__unix__)

#include <syslog.h>

static const char *syslogLevelNames[6] = {"trace", "debug", "info",
                                   "warn", "error", "fatal"};
static const char *syslogCategoryNames[UA_LOGCATEGORIES] =
    {"network", "channel", "session", "server", "client",
     "application", "security", "eventloop", "pubsub", "discovery"};

#ifdef __clang__
__attribute__((__format__(__printf__, 4 , 0)))
#endif
static void
UA_Log_Syslog_log(void *context, UA_LogLevel level, UA_LogCategory category,
                  const char *msg, va_list args) {
    /* Assume that context is casted to UA_LogLevel */
    if(context != NULL && (UA_LogLevel)(uintptr_t)context > level)
        return;

    int priority = LOG_INFO;
    switch(level) {
    case UA_LOGLEVEL_DEBUG:
        priority = LOG_DEBUG;
        break;
    case UA_LOGLEVEL_INFO:
        priority = LOG_INFO;
        break;
    case UA_LOGLEVEL_WARNING:
        priority = LOG_WARNING;
        break;
    case UA_LOGLEVEL_ERROR:
        priority = LOG_ERR;
        break;
    case UA_LOGLEVEL_FATAL:
        priority = LOG_CRIT;
        break;
    case UA_LOGLEVEL_TRACE:
    default:
        return;
    }

    int logLevelSlot = ((int)level / 100) - 1;

#define LOGBUFSIZE 512
    char logbuf[LOGBUFSIZE];
    int pos = mp_snprintf(logbuf, LOGBUFSIZE, "[%s/%s] ",
                          syslogLevelNames[logLevelSlot],
                          syslogCategoryNames[category]);
    if(pos < 0) {
        syslog(LOG_WARNING, "Log message too long for syslog");
        return;
    }
    pos = mp_vsnprintf(&logbuf[pos], LOGBUFSIZE - (size_t)pos, msg, args);
    if(pos < 0) {
        syslog(LOG_WARNING, "Log message too long for syslog");
        return;
    }

    syslog(priority, "%s", logbuf);
}

static void
UA_Log_Syslog_clear(UA_Logger *logger) {
    /* closelog is optional. We don't use it as several loggers might be
     * instantiated in parallel. */
    /* closelog(); */
    UA_free(logger);
}

UA_Logger
UA_Log_Syslog(void) {
    return UA_Log_Syslog_withLevel(UA_LOGLEVEL_TRACE);
}

UA_Logger
UA_Log_Syslog_withLevel(UA_LogLevel minlevel) {
    UA_Logger logger = {UA_Log_Syslog_log, (void*)(uintptr_t)minlevel, NULL};
    return logger;
}

UA_Logger *
UA_Log_Syslog_new(UA_LogLevel minlevel) {
    UA_Logger *logger = (UA_Logger*)UA_malloc(sizeof(UA_Logger));
    if(!logger)
        return NULL;
    *logger = UA_Log_Syslog_withLevel(minlevel);
    logger->clear = UA_Log_Syslog_clear;
    return logger;
}

#endif

/**** amalgamated original file "/plugins/crypto/ua_filestore_common.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */



#ifdef UA_ENABLE_ENCRYPTION

#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__)


UA_StatusCode
readFileToByteString(const char *const path,
                     UA_ByteString *data);

UA_StatusCode
writeByteStringToFile(const char *const path,
                      const UA_ByteString *data);

#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__) */

#endif /* UA_ENABLE_ENCRYPTION */


/**** amalgamated original file "/plugins/crypto/ua_filestore_common.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_ENCRYPTION

#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__)

#ifdef UA_ARCHITECTURE_WIN32
/* TODO: Replace with a proper dirname implementation. This is a just minimal
 * implementation working with correct input data. */
char *
_UA_dirname_minimal(char *path) {
    if(path == NULL || *path == '\0')
        return ".";
    char *lastSlash = strrchr(path, '/');
    if(lastSlash == NULL)
        return ".";
    *lastSlash = 0;
    return path;
}
#endif /* UA_ARCHITECTURE_WIN32 */

UA_StatusCode
readFileToByteString(const char *const path, UA_ByteString *data) {
    if(path == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Open the file */
    UA_FILE *fp = UA_fopen(path, "rb");
    if(!fp)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Get the file length, allocate the data and read */
    UA_fseek(fp, 0, UA_SEEK_END);
    long fileSize = UA_ftell(fp);
    if(fileSize < 0) {
        UA_fclose(fp);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_StatusCode retval = UA_ByteString_allocBuffer(data, (size_t)fileSize);
    if(retval == UA_STATUSCODE_GOOD) {
        UA_fseek(fp, 0, UA_SEEK_SET);
        size_t read = UA_fread(data->data, sizeof(UA_Byte), data->length * sizeof(UA_Byte), fp);
        if(read != data->length) {
            UA_ByteString_clear(data);
        }
    } else {
        data->length = 0;
    }
    UA_fclose(fp);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
writeByteStringToFile(const char *const path, const UA_ByteString *data) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Open the file */
    UA_FILE *fp = UA_fopen(path, "wb");
    if(!fp)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Write byte string to file */
    size_t len = UA_fwrite(data->data, sizeof(UA_Byte), data->length * sizeof(UA_Byte), fp);
    if(len != data->length)
        retval = UA_STATUSCODE_BADINTERNALERROR;

    UA_fclose(fp);
    return retval;
}

#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__) */

#endif /* UA_ENABLE_ENCRYPTION */

/**** amalgamated original file "/plugins/crypto/ua_certificategroup_filestore.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Kai Huebl)
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */



#ifdef UA_ENABLE_ENCRYPTION

#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || defined(__APPLE__)

#ifdef __linux__
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUF_LEN (1024 * ( EVENT_SIZE + 16 ))
#endif /* __linux__ */

typedef struct {
    /* Memory cert store as a base */
    UA_CertificateGroup *store;

#ifdef __linux__
    int inotifyFd;
#endif /* __linux__ */

    UA_String trustedCertFolder;
    UA_String trustedCrlFolder;
    UA_String issuerCertFolder;
    UA_String issuerCrlFolder;
    UA_String rejectedCertFolder;
    UA_String ownCertFolder;
    UA_String ownKeyFolder;
    UA_String rootFolder;
} FileCertStore;

static int
mkpath(char *dir, UA_MODE mode) {
    if(dir == NULL)
        return 1;

    char *path = (char*)UA_malloc(strlen(dir) + 1);
    if(!path)
        return 1;
    strcpy(path, dir);

    char *pos = path;
    if(pos[0] == '/')
        pos++;

    for(; *pos; pos++) {
        if(*pos != '/')
            continue;

        *pos = '\0';
        if(path[0] != '\0' && UA_mkdir(path, mode) != 0 && errno != EEXIST) {
            UA_free(path);
            return 1;
        }
        *pos = '/';
    }

    if(UA_mkdir(path, mode) != 0 && errno != EEXIST) {
        UA_free(path);
        return 1;
    }

    UA_free(path);
    return 0;
}

static UA_StatusCode
removeAllFilesFromDir(const char *const path, bool removeSubDirs) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Check parameter */
    if(path == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* remove all regular files from directory */
    UA_DIR *dir = UA_opendir(path);
    if(!dir)
        return UA_STATUSCODE_BADINTERNALERROR;

    struct UA_DIRENT *dirent;
    while((dirent = UA_readdir(dir)) != NULL) {
        if(dirent->d_type == UA_DT_REG) {
            char file_name[UA_FILENAME_MAX];
            mp_snprintf(file_name, UA_FILENAME_MAX, "%s/%s", path,
                        (char *)dirent->d_name);
            UA_remove(file_name);
        }
        if(dirent->d_type == UA_DT_DIR && removeSubDirs == true) {
            char *directory = (char*)dirent->d_name;

            char dir_name[UA_FILENAME_MAX];
            mp_snprintf(dir_name, UA_FILENAME_MAX, "%s/%s", path, (char *)dirent->d_name);

            if(strlen(directory) == 1 && directory[0] == '.')
                continue;
            if(strlen(directory) == 2 && directory[0] == '.' && directory[1] == '.')
                continue;

            retval = removeAllFilesFromDir(dir_name, removeSubDirs);
        }
    }
    UA_closedir(dir);

    return retval;
}

static UA_StatusCode
getCertFileName(const char *path, const UA_ByteString *certificate,
                char *fileNameBuf, size_t fileNameLen) {
    /* Check parameter */
    if(path == NULL || certificate == NULL || fileNameBuf == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    UA_String thumbprint = UA_STRING_NULL;
    thumbprint.length = 40;
    thumbprint.data = (UA_Byte*)UA_calloc(thumbprint.length, sizeof(UA_Byte));

    UA_String subjectName = UA_STRING_NULL;

    UA_CertificateUtils_getThumbprint((UA_ByteString*)(uintptr_t)certificate, &thumbprint);
    UA_CertificateUtils_getSubjectName((UA_ByteString*)(uintptr_t)certificate, &subjectName);

    if((thumbprint.length + subjectName.length + 2) > fileNameLen) {
        UA_String_clear(&thumbprint);
        UA_String_clear(&subjectName);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    char *thumbprintBuffer = (char*)UA_malloc(thumbprint.length + 1);
    char *subjectNameBuffer = (char*)UA_malloc(subjectName.length + 1);

    memcpy(thumbprintBuffer, thumbprint.data, thumbprint.length);
    thumbprintBuffer[thumbprint.length] = '\0';
    memcpy(subjectNameBuffer, subjectName.data, subjectName.length);
    subjectNameBuffer[subjectName.length] = '\0';

    char *subName = NULL;
    char *substring = "CN=";
    char *ptr = strstr(subjectNameBuffer, substring);

    if(ptr != NULL) {
        subName = ptr + 3;
    } else {
        subName = subjectNameBuffer;
    }

    if(mp_snprintf(fileNameBuf, fileNameLen, "%s/%s[%s]", path, subName,
                   thumbprintBuffer) < 0)
        retval = UA_STATUSCODE_BADINTERNALERROR;

    UA_String_clear(&thumbprint);
    UA_String_clear(&subjectName);
    UA_free(thumbprintBuffer);
    UA_free(subjectNameBuffer);

    return retval;
}

static bool
isRegularFile(const char *path, const struct UA_DIRENT *dirent) {
    if(dirent->d_type == UA_DT_DIR)
        return false;
    if(dirent->d_type == UA_DT_REG)
        return true;

#ifndef UA_ARCHITECTURE_WIN32
    char filename[UA_PATH_MAX] = {0};
    int len = mp_snprintf(filename, UA_PATH_MAX, "%s/%s", path, dirent->d_name);
    if(len < 0 || len >= UA_PATH_MAX)
        return false;

    struct UA_STAT statBuf;
    return (UA_stat(filename, &statBuf) == 0 && S_ISREG(statBuf.st_mode));
#else
    return false;
#endif
}

static UA_StatusCode
readCertificates(UA_ByteString **list, size_t *listSize, const UA_String path) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    char listPath[UA_PATH_MAX] = {0};
    int pathLen = mp_snprintf(listPath, UA_PATH_MAX, "%.*s",
                              (int)path.length, (char*)path.data);
    if(pathLen < 0 || pathLen >= UA_PATH_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Determine number of certificates */
    size_t numCerts = 0;
    UA_DIR *dir = UA_opendir(listPath);
    if(!dir) {
        if(mkpath(listPath, 0777) != 0)
            return UA_STATUSCODE_BADINTERNALERROR;
        dir = UA_opendir(listPath);
        if(!dir)
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    struct UA_DIRENT *dirent;
    while((dirent = UA_readdir(dir)) != NULL) {
        if(!isRegularFile(listPath, dirent))
            continue;
        numCerts++;
    }

    retval = UA_Array_resize((void **)list, listSize, numCerts, &UA_TYPES[UA_TYPES_BYTESTRING]);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_closedir(dir);
        return retval;
    }

    /* Read files from directory */
    size_t numActCerts = 0;
    UA_rewinddir(dir);

    while((dirent = UA_readdir(dir)) != NULL) {
        if(!isRegularFile(listPath, dirent))
            continue;
        if(numActCerts < numCerts) {
            /* Create filename to load */
            char filename[UA_PATH_MAX] = {0};
            if(mp_snprintf(filename, UA_PATH_MAX, "%s/%s", listPath, dirent->d_name) < 0) {
                UA_closedir(dir);
                return UA_STATUSCODE_BADINTERNALERROR;
            }

            /* Load data from file */
            retval = readFileToByteString(filename, &((*list)[numActCerts]));
            if(retval != UA_STATUSCODE_GOOD) {
                UA_closedir(dir);
                return retval;
            }
        }
        numActCerts++;
    }
    UA_closedir(dir);

    return retval;
}

static UA_StatusCode
readTrustStore(UA_CertificateGroup *certGroup, UA_TrustListDataType *trustList) {
    if(certGroup == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    retval |= readCertificates(&trustList->trustedCertificates, &trustList->trustedCertificatesSize,
                               context->trustedCertFolder);
    retval |= readCertificates(&trustList->trustedCrls, &trustList->trustedCrlsSize,
                               context->trustedCrlFolder);
    retval |= readCertificates(&trustList->issuerCertificates, &trustList->issuerCertificatesSize,
                               context->issuerCertFolder);
    retval |= readCertificates(&trustList->issuerCrls, &trustList->issuerCrlsSize,
                               context->issuerCrlFolder);

    return retval;
}

static UA_StatusCode
reloadAndWriteTrustStore(UA_CertificateGroup *certGroup) {
    FileCertStore *context = (FileCertStore *)certGroup->context;

    UA_TrustListDataType trustList;
    UA_TrustListDataType_init(&trustList);
    trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;

    UA_StatusCode retval = readTrustStore(certGroup, &trustList);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_TrustListDataType_clear(&trustList);
        return retval;
    }

    retval = context->store->setTrustList(context->store, &trustList);
    UA_TrustListDataType_clear(&trustList);

    return retval;
}

static UA_StatusCode
reloadTrustStore(UA_CertificateGroup *certGroup) {
    if(certGroup == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

 #ifdef __linux__
    FileCertStore *context = (FileCertStore *)certGroup->context;

    char buffer[BUF_LEN];
    const ssize_t length = read(context->inotifyFd, buffer, BUF_LEN );
    if(length == -1 && errno != EAGAIN)
        return UA_STATUSCODE_BADINTERNALERROR;
#else
    /* TODO: Implement a way to check for changes in the pki folder */
    const ssize_t length = 0;
#endif /* __linux__ */

    /* No events, which means no changes to the pki folder */
    /* If the nonblocking read() found no events to read, then
     * it returns -1 with errno set to EAGAIN. In that case,
     * we exit the loop. */
    if(length <= 0)
        return UA_STATUSCODE_GOOD;

    return reloadAndWriteTrustStore(certGroup);
}

static UA_StatusCode
writeCertificates(UA_CertificateGroup *certGroup, const UA_ByteString *list,
                  size_t listSize, const char *listPath) {
    /* Check parameter */
    if(listPath == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(listSize > 0 && list == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < listSize; i++) {
        /* Create filename to load */
        char filename[UA_PATH_MAX] = {0};
        retval = getCertFileName(listPath, &list[i], filename, UA_PATH_MAX);
        if(retval != UA_STATUSCODE_GOOD)
            return UA_STATUSCODE_BADINTERNALERROR;

        /* Store data in file */
        retval = writeByteStringToFile(filename, &list[i]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    return retval;
}

static UA_StatusCode
writeTrustList(UA_CertificateGroup *certGroup, const UA_ByteString *list,
               size_t listSize, const UA_String path) {
    /* Check parameter */
    if(path.length == 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(listSize > 0 && list == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    char listPath[UA_PATH_MAX] = {0};
    mp_snprintf(listPath, UA_PATH_MAX, "%.*s", (int)path.length, (char *)path.data);
    /* remove existing files in directory */
    UA_StatusCode retval = removeAllFilesFromDir(listPath, false);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return writeCertificates(certGroup, list, listSize, listPath);
}

static UA_StatusCode
writeTrustStore(UA_CertificateGroup *certGroup, const UA_UInt32 trustListMask) {
    /* Check parameter */
    if(certGroup == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;

    UA_TrustListDataType trustList;
    UA_TrustListDataType_init(&trustList);
    trustList.specifiedLists = trustListMask;

    context->store->getTrustList(context->store, &trustList);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(trustList.specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES) {
        retval = writeTrustList(certGroup, trustList.trustedCertificates,
                                trustList.trustedCertificatesSize, context->trustedCertFolder);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }
    if(trustList.specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCRLS) {
        retval = writeTrustList(certGroup, trustList.trustedCrls,
                                trustList.trustedCrlsSize, context->trustedCrlFolder);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }
    if(trustList.specifiedLists & UA_TRUSTLISTMASKS_ISSUERCERTIFICATES) {
        retval = writeTrustList(certGroup, trustList.issuerCertificates,
                                trustList.issuerCertificatesSize, context->issuerCertFolder);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }
    if(trustList.specifiedLists & UA_TRUSTLISTMASKS_ISSUERCRLS) {
        retval = writeTrustList(certGroup, trustList.issuerCrls,
                                trustList.issuerCrlsSize, context->issuerCrlFolder);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }
    UA_TrustListDataType_clear(&trustList);

    return retval;
}

static UA_StatusCode
FileCertStore_setupStorePath(char *directory, char *rootDirectory,
                             size_t rootDirectorySize, UA_String *out,
                             const UA_Logger *logger) {
    char path[UA_PATH_MAX] = {0};
    int pathLen = mp_snprintf(path, UA_PATH_MAX, "%.*s%s",
                              (int)rootDirectorySize, rootDirectory, directory);
    if(pathLen < 0 || pathLen >= UA_PATH_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;

    *out = UA_STRING_ALLOC(path);
    if(out->data == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    if(mkpath(path, 0777) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_APPLICATION,
                     "Could not create PKI directory %s (errno %i)", path, errno);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
FileCertStore_createPkiDirectory(UA_CertificateGroup *certGroup, const UA_String directory) {
    if(certGroup == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;
    if(!context)
        return UA_STATUSCODE_BADINTERNALERROR;

    char rootDirectory[UA_PATH_MAX] = {0};
    size_t rootDirectorySize = 0;

    if(directory.length <= 0 || directory.length >= UA_PATH_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;

    memcpy(rootDirectory, directory.data, directory.length);
    rootDirectorySize = strnlen(rootDirectory, UA_PATH_MAX);

    /* Add Certificate Group Id */
    UA_NodeId applCertGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    UA_NodeId httpCertGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTHTTPSGROUP);
    UA_NodeId userTokenCertGroup =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);

    if(UA_NodeId_equal(&certGroup->certificateGroupId, &applCertGroup)) {
        strncpy(&rootDirectory[rootDirectorySize], "/ApplCerts", UA_PATH_MAX - rootDirectorySize);
    } else if(UA_NodeId_equal(&certGroup->certificateGroupId, &httpCertGroup)) {
        strncpy(&rootDirectory[rootDirectorySize], "/HttpCerts", UA_PATH_MAX - rootDirectorySize);
    } else if(UA_NodeId_equal(&certGroup->certificateGroupId, &userTokenCertGroup)) {
        strncpy(&rootDirectory[rootDirectorySize], "/UserTokenCerts", UA_PATH_MAX - rootDirectorySize);
    } else {
        UA_String nodeIdStr;
        UA_String_init(&nodeIdStr);
        UA_NodeId_print(&certGroup->certificateGroupId, &nodeIdStr);
        strncpy(&rootDirectory[rootDirectorySize], (char *)nodeIdStr.data, UA_PATH_MAX - rootDirectorySize);
        UA_String_clear(&nodeIdStr);
    }
    rootDirectorySize = strnlen(rootDirectory, UA_PATH_MAX);

    context->rootFolder = UA_STRING_ALLOC(rootDirectory);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    retval |= FileCertStore_setupStorePath("/trusted/certs", rootDirectory,
                                           rootDirectorySize, &context->trustedCertFolder,
                                           certGroup->logging);
    retval |= FileCertStore_setupStorePath("/trusted/crl", rootDirectory,
                                           rootDirectorySize, &context->trustedCrlFolder,
                                           certGroup->logging);
    retval |= FileCertStore_setupStorePath("/issuer/certs", rootDirectory,
                                           rootDirectorySize, &context->issuerCertFolder,
                                           certGroup->logging);
    retval |= FileCertStore_setupStorePath("/issuer/crl", rootDirectory,
                                           rootDirectorySize, &context->issuerCrlFolder,
                                           certGroup->logging);
    retval |= FileCertStore_setupStorePath("/rejected/certs", rootDirectory,
                                           rootDirectorySize, &context->rejectedCertFolder,
                                           certGroup->logging);
    retval |= FileCertStore_setupStorePath("/own/certs", rootDirectory,
                                           rootDirectorySize, &context->ownCertFolder,
                                           certGroup->logging);
    retval |= FileCertStore_setupStorePath("/own/private", rootDirectory,
                                           rootDirectorySize, &context->ownKeyFolder,
                                           certGroup->logging);

    return retval;
}

#ifdef __linux__

static UA_StatusCode
FileCertStore_createInotifyEvent(UA_CertificateGroup *certGroup) {
    if(certGroup == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;

    context->inotifyFd = inotify_init1(IN_NONBLOCK);
    if(context->inotifyFd == -1)
        return UA_STATUSCODE_BADINTERNALERROR;

    char folder[UA_PATH_MAX] = {0};
    mp_snprintf(folder, UA_PATH_MAX, "%.*s",
                (int)context->rootFolder.length, (char*)context->rootFolder.data);
    int wd = inotify_add_watch(context->inotifyFd, folder, IN_ALL_EVENTS);
    if(wd == -1) {
        close(context->inotifyFd);
        context->inotifyFd = -1;
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    mp_snprintf(folder, UA_PATH_MAX, "%.*s",
                (int)context->trustedCertFolder.length, (char*)context->trustedCertFolder.data);
    wd = inotify_add_watch(context->inotifyFd, folder, IN_ALL_EVENTS);
    if(wd == -1) {
        close(context->inotifyFd);
        context->inotifyFd = -1;
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    return UA_STATUSCODE_GOOD;
}

#endif /* __linux__ */

static UA_StatusCode
FileCertStore_getTrustList(UA_CertificateGroup *certGroup, UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;
    /* It will only re-read the Cert store on the file system if there have been changes to files. */
    UA_StatusCode retval = reloadTrustStore(certGroup);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return context->store->getTrustList(context->store, trustList);
}

static UA_StatusCode
FileCertStore_setTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;
    /* It will only re-read the Cert store on the file system if there have been changes to files. */
    UA_StatusCode retval = reloadTrustStore(certGroup);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = context->store->setTrustList(context->store, trustList);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return writeTrustStore(certGroup, trustList->specifiedLists);
}

static UA_StatusCode
FileCertStore_addToTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;
    /* It will only re-read the Cert store on the file system if there have been changes to files. */
    UA_StatusCode retval = reloadTrustStore(certGroup);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = context->store->addToTrustList(context->store, trustList);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return writeTrustStore(certGroup, trustList->specifiedLists);
}

static UA_StatusCode
FileCertStore_removeFromTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;
    /* It will only re-read the Cert store on the file system if there have been changes to files. */
    UA_StatusCode retval = reloadTrustStore(certGroup);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = context->store->removeFromTrustList(context->store, trustList);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return writeTrustStore(certGroup, trustList->specifiedLists);
}

static UA_StatusCode
FileCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **rejectedList, size_t *rejectedListSize) {
    /* Check parameter */
    if(certGroup == NULL || rejectedList == NULL || rejectedListSize == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    FileCertStore *context = (FileCertStore *)certGroup->context;
    return context->store->getRejectedList(context->store, rejectedList, rejectedListSize);
}

static UA_StatusCode
FileCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
                                 const UA_Boolean isTrusted, UA_ByteString **crls,
                                 size_t *crlsSize) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL || crls == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    FileCertStore *context = (FileCertStore *)certGroup->context;
    /* It will only re-read the Cert store on the file system if there have been changes to files. */
    UA_StatusCode retval = reloadTrustStore(certGroup);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return context->store->getCertificateCrls(context->store, certificate, isTrusted, crls, crlsSize);
}

static UA_StatusCode
FileCertStore_verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    FileCertStore *context = (FileCertStore *)certGroup->context;
    /* It will only re-read the Cert store on the file system if there have been changes to files. */
    UA_StatusCode retval = reloadTrustStore(certGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        return retval;
    }

    retval = context->store->verifyCertificate(context->store, certificate);
    if(retval == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED ||
       retval == UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED ||
       retval == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN ||
       retval == UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN) {
        /* write rejectedList to filestore */
        UA_ByteString *rejectedList = NULL;
        size_t rejectedListSize = 0;
        context->store->getRejectedList(context->store, &rejectedList, &rejectedListSize);
        writeTrustList(certGroup, rejectedList, rejectedListSize, context->rejectedCertFolder);
        UA_Array_delete(rejectedList, rejectedListSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
    }

    return retval;
}

static void
FileCertStore_clear(UA_CertificateGroup *certGroup) {
    /* check parameter */
    if(!certGroup || !certGroup->context)
        return;

    UA_NodeId_clear(&certGroup->certificateGroupId);

    FileCertStore *context = (FileCertStore *)certGroup->context;

    if(context->store) {
        context->store->clear(context->store);
        UA_free(context->store);
    }
    UA_String_clear(&context->trustedCertFolder);
    UA_String_clear(&context->trustedCrlFolder);
    UA_String_clear(&context->issuerCertFolder);
    UA_String_clear(&context->issuerCrlFolder);
    UA_String_clear(&context->rejectedCertFolder);
    UA_String_clear(&context->ownCertFolder);
    UA_String_clear(&context->ownKeyFolder);
    UA_String_clear(&context->rootFolder);

#ifdef __linux__
    if(context->inotifyFd > 0)
        close(context->inotifyFd);
#endif /* __linux__ */

    UA_free(context);
    certGroup->context = NULL;
}

UA_StatusCode
UA_CertificateGroup_Filestore(UA_CertificateGroup *certGroup,
                              UA_NodeId *certificateGroupId,
                              const UA_String storePath,
                              const UA_Logger *logger,
                              const UA_KeyValueMap *params) {
    if(certGroup == NULL || certificateGroupId == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Clear if the plugin is already initialized */
    if(certGroup->clear)
        certGroup->clear(certGroup);

    UA_NodeId_copy(certificateGroupId, &certGroup->certificateGroupId);
    certGroup->logging = logger;

    certGroup->getTrustList = FileCertStore_getTrustList;
    certGroup->setTrustList = FileCertStore_setTrustList;
    certGroup->addToTrustList = FileCertStore_addToTrustList;
    certGroup->removeFromTrustList = FileCertStore_removeFromTrustList;
    certGroup->getRejectedList = FileCertStore_getRejectedList;
    certGroup->getCertificateCrls = FileCertStore_getCertificateCrls;
    certGroup->verifyCertificate = FileCertStore_verifyCertificate;
    certGroup->clear = FileCertStore_clear;

    /* Set PKI Store context data */
    FileCertStore *context = (FileCertStore *)UA_calloc(1, sizeof(FileCertStore));
    if(!context) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }
    certGroup->context = context;

    retval = FileCertStore_createPkiDirectory(certGroup, storePath);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_APPLICATION,
                     "Could not create the PKI directory structure");
        goto cleanup;
    }

    context->store = (UA_CertificateGroup*)UA_calloc(1, sizeof(UA_CertificateGroup));
    retval = UA_CertificateGroup_Memorystore(context->store, certificateGroupId, NULL, logger, params);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_APPLICATION,
                     "Could not initialize the PKI memory store");
        goto cleanup;
    }

#ifdef __linux__
    retval = FileCertStore_createInotifyEvent(certGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        goto cleanup;
    }
#endif /* __linux__ */

    retval = reloadAndWriteTrustStore(certGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_APPLICATION,
                     "Could not load the PKI trust store from the filestore");
        goto cleanup;
    }

    return UA_STATUSCODE_GOOD;

    cleanup:
        certGroup->clear(certGroup);
    return retval;
}

#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */

#endif /* UA_ENABLE_ENCRYPTION */

/**** amalgamated original file "/plugins/crypto/ua_securitypolicy_filestore.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Kai Huebl)
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */



#ifdef UA_ENABLE_ENCRYPTION

#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)

/* In-Memory security policy as a base */
typedef struct {
    UA_SecurityPolicy *innerPolicy;
    UA_String storePath;
} Filestore_Context;

static bool
checkCertificateInFilestore(char *path, const UA_ByteString newCertificate) {
    /* Check if the file is already stored in CertStore */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    bool isStored = false;
    UA_ByteString fileData = UA_BYTESTRING_NULL;
    UA_DIR *dir = UA_opendir(path);
    if(!dir)
        return UA_STATUSCODE_BADINTERNALERROR;

    struct UA_DIRENT *dirent;
    while((dirent = UA_readdir(dir)) != NULL) {
        if(dirent->d_type != UA_DT_REG)
            continue;

        /* Get filename to load */
        char filename[UA_FILENAME_MAX];
        if(mp_snprintf(filename, UA_FILENAME_MAX, "%s/%s", path, dirent->d_name) < 0)
            return false;

        /* Load data from file */
        if(fileData.length > 0)
            UA_ByteString_clear(&fileData);
        retval = readFileToByteString(filename, &fileData);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;

        /* check if new certificate is already stored */
        if(UA_ByteString_equal(&newCertificate, &fileData)) {
            isStored = true;
            goto cleanup;
        }
    }

cleanup:
    if(fileData.length > 0)
        UA_ByteString_clear(&fileData);
    UA_closedir(dir);

    return isStored;
}

static UA_StatusCode
createCertName(const UA_ByteString *certificate, char *fileNameBuf, size_t fileNameLen) {
    /* Check parameter */
    if(certificate == NULL || fileNameBuf == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    UA_String thumbprint = UA_STRING_NULL;
    thumbprint.length = 40;
    thumbprint.data = (UA_Byte*)UA_calloc(thumbprint.length, sizeof(UA_Byte));

    UA_String subjectName = UA_STRING_NULL;

    UA_CertificateUtils_getThumbprint((UA_ByteString*)(uintptr_t)certificate, &thumbprint);
    UA_CertificateUtils_getSubjectName((UA_ByteString*)(uintptr_t)certificate, &subjectName);

    if((thumbprint.length + subjectName.length + 2) > fileNameLen) {
        UA_String_clear(&thumbprint);
        UA_String_clear(&subjectName);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    char *thumbprintBuffer = (char*)UA_calloc(1, thumbprint.length + 1);
    char *subjectNameBuffer = (char*)UA_calloc(1, subjectName.length + 1);

    memcpy(thumbprintBuffer, thumbprint.data, thumbprint.length);
    memcpy(subjectNameBuffer, subjectName.data, subjectName.length);

    char *subName = NULL;
    char *substring = "CN=";
    char *ptr = strstr(subjectNameBuffer, substring);

    if(ptr != NULL) {
        subName = ptr + 3;
    } else {
        subName = subjectNameBuffer;
    }

    if(mp_snprintf(fileNameBuf, fileNameLen, "%s[%s]", subName, thumbprintBuffer) < 0)
        retval = UA_STATUSCODE_BADINTERNALERROR;

    UA_String_clear(&thumbprint);
    UA_String_clear(&subjectName);
    UA_free(thumbprintBuffer);
    UA_free(subjectNameBuffer);

    return retval;
}


static UA_StatusCode
writeCertificateAndPrivateKeyToFilestore(const UA_String storePath,
                                         const UA_ByteString newCertificate,
                                         const UA_ByteString newPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Create the paths to the certificates and private key folders */
    char ownCertPathDir[UA_PATH_MAX];
    if(mp_snprintf(ownCertPathDir, UA_PATH_MAX, "%.*s%s", (int)storePath.length,
                   (char *)storePath.data, "/ApplCerts/own/certs") < 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    char ownKeyPathDir[UA_PATH_MAX];
    if(mp_snprintf(ownKeyPathDir, UA_PATH_MAX, "%.*s%s", (int)storePath.length,
                   (char *)storePath.data, "/ApplCerts/own/private") < 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Check if certificate is already stored */
    if(checkCertificateInFilestore(ownCertPathDir, newCertificate))
        return UA_STATUSCODE_GOOD;

    /* Create filename for new certificate */
    char newFilename[UA_PATH_MAX];
    retval = createCertName(&newCertificate, newFilename, UA_PATH_MAX);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    char newCertFilename[UA_PATH_MAX];
    if(mp_snprintf(newCertFilename, UA_PATH_MAX, "%s/%s%s",
                   ownCertPathDir, newFilename, ".der") < 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    char newKeyFilename[UA_PATH_MAX];
    if(mp_snprintf(newKeyFilename, UA_PATH_MAX, "%s/%s%s",
                   ownKeyPathDir, newFilename, ".key") < 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    retval = writeByteStringToFile(newCertFilename, &newCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Write new private key only if it is set */
    if(newPrivateKey.length > 0)
        return writeByteStringToFile(newKeyFilename, &newPrivateKey);
    else
        return UA_STATUSCODE_GOOD;
}

/************************/
/* Asymmetric Signature */
/************************/

static UA_StatusCode
asym_verify_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                      const UA_ByteString *message, const UA_ByteString *signature) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymSignatureAlgorithm.verify(isp, channelContext, message, signature);
}

static UA_StatusCode
asym_sign_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                    const UA_ByteString *message, UA_ByteString *signature) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymSignatureAlgorithm.sign(isp, channelContext, message, signature);
}

static size_t
asym_getLocalSignatureSize_filestore(const UA_SecurityPolicy *sp,
                                     const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymSignatureAlgorithm.getLocalSignatureSize(isp, channelContext);
}

static size_t
asym_getRemoteSignatureSize_filestore(const UA_SecurityPolicy *sp,
                                     const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymSignatureAlgorithm.getRemoteSignatureSize(isp, channelContext);
}

static size_t
asymSig_getLocalKeyLength_filestore(const UA_SecurityPolicy *sp,
                                    const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymSignatureAlgorithm.getLocalKeyLength(isp, channelContext);
}

static size_t
asymSig_getRemoteKeyLength_filestore(const UA_SecurityPolicy *sp,
                                    const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymSignatureAlgorithm.getRemoteKeyLength(isp, channelContext);
}

/*************************/
/* Asymmetric Encryption */
/*************************/

static UA_StatusCode
asym_encrypt_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                       UA_ByteString *data) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymEncryptionAlgorithm.encrypt(isp, channelContext, data);
}

static UA_StatusCode
asym_decrypt_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                       UA_ByteString *data) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymEncryptionAlgorithm.decrypt(isp, channelContext, data);
}

static size_t
asym_getLocalKeyLength_filestore(const UA_SecurityPolicy *sp,
                                 const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymEncryptionAlgorithm.getLocalKeyLength(isp, channelContext);
}

static size_t
asym_getRemoteKeyLength_filestore(const UA_SecurityPolicy *sp,
                                  const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymEncryptionAlgorithm.getRemoteKeyLength(isp, channelContext);
}

static size_t
asym_getRemotePlainTextBlockSize_filestore(const UA_SecurityPolicy *sp,
                                           const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymEncryptionAlgorithm.getRemotePlainTextBlockSize(isp, channelContext);
}

static size_t
asym_getRemoteBlockSize_filestore(const UA_SecurityPolicy *sp,
                                  const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->asymEncryptionAlgorithm.getRemoteBlockSize(isp, channelContext);
}

/***********************/
/* Symmetric Signature */
/***********************/

static UA_StatusCode
sym_verify_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                     const UA_ByteString *message, const UA_ByteString *signature) {
    Filestore_Context *pc =
        (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symSignatureAlgorithm.verify(isp, channelContext, message, signature);
}

static UA_StatusCode
sym_sign_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                   const UA_ByteString *message, UA_ByteString *signature) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symSignatureAlgorithm.sign(isp, channelContext, message, signature);
}

static size_t
sym_getLocalSignatureSize_filestore(const UA_SecurityPolicy *sp,
                                    const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symSignatureAlgorithm.getLocalSignatureSize(isp, channelContext);
}

static size_t
sym_getRemoteSignatureSize_filestore(const UA_SecurityPolicy *sp,
                                     const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symSignatureAlgorithm.getRemoteSignatureSize(isp, channelContext);
}

static size_t
symSig_getLocalKeyLength_filestore(const UA_SecurityPolicy *sp,
                                    const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symSignatureAlgorithm.getLocalKeyLength(isp, channelContext);
}

static size_t
symSig_getRemoteKeyLength_filestore(const UA_SecurityPolicy *sp,
                                    const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symSignatureAlgorithm.getRemoteKeyLength(isp, channelContext);
}

/*************************/
/* Asymmetric Encryption */
/*************************/

static UA_StatusCode
sym_encrypt_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                      UA_ByteString *data) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symEncryptionAlgorithm.encrypt(isp, channelContext, data);
}

static UA_StatusCode
sym_decrypt_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                      UA_ByteString *data) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symEncryptionAlgorithm.decrypt(isp, channelContext, data);
}

static size_t
sym_getLocalKeyLength_filestore(const UA_SecurityPolicy *sp,
                                const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symEncryptionAlgorithm.getLocalKeyLength(isp, channelContext);
}

static size_t
sym_getRemoteKeyLength_filestore(const UA_SecurityPolicy *sp,
                                 const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symEncryptionAlgorithm.getRemoteKeyLength(isp, channelContext);
}

static size_t
sym_getRemotePlainTextBlockSize_filestore(const UA_SecurityPolicy *sp,
                                          const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symEncryptionAlgorithm.getRemotePlainTextBlockSize(isp, channelContext);
}

static size_t
sym_getRemoteBlockSize_filestore(const UA_SecurityPolicy *sp,
                                 const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->symEncryptionAlgorithm.getRemoteBlockSize(isp, channelContext);
}

/*************************/
/* Certificate Signature */
/*************************/

static UA_StatusCode
cert_verify_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                      const UA_ByteString *message, const UA_ByteString *signature) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->certSignatureAlgorithm.verify(isp, channelContext, message, signature);
}

static UA_StatusCode
cert_sign_filestore(const UA_SecurityPolicy *sp, void *channelContext,
                    const UA_ByteString *message, UA_ByteString *signature) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->certSignatureAlgorithm.sign(isp, channelContext, message, signature);
}

static size_t
cert_getLocalSignatureSize_filestore(const UA_SecurityPolicy *sp,
                                     const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->certSignatureAlgorithm.getLocalSignatureSize(isp, channelContext);
}

static size_t
cert_getRemoteSignatureSize_filestore(const UA_SecurityPolicy *sp,
                                     const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->certSignatureAlgorithm.getRemoteSignatureSize(isp, channelContext);
}


static size_t
cert_getLocalKeyLength_filestore(const UA_SecurityPolicy *sp,
                                 const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->certSignatureAlgorithm.getLocalKeyLength(isp, channelContext);
}

static size_t
cert_getRemoteKeyLength_filestore(const UA_SecurityPolicy *sp,
                                  const void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->certSignatureAlgorithm.getRemoteKeyLength(isp, channelContext);
}

/********************/
/* Direct Callbacks */
/********************/

static UA_StatusCode
newChannelContext_filestore(const UA_SecurityPolicy *sp,
                            const UA_ByteString *remoteCertificate,
                            void **pp_contextData) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->newChannelContext(isp, remoteCertificate, pp_contextData);
}

static void
deleteChannelContext_filestore(const UA_SecurityPolicy *sp, void *channelContext) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    isp->deleteChannelContext(isp, channelContext);
}

static UA_StatusCode
setLocalSymSigningKey_filestore(const UA_SecurityPolicy *sp,
                                   void *channelContext, const UA_ByteString *key) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->setLocalSymSigningKey(isp, channelContext, key);
}

static UA_StatusCode
setLocalSymEncryptingKey_filestore(const UA_SecurityPolicy *sp,
                                      void *channelContext, const UA_ByteString *key) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->setLocalSymEncryptingKey(isp, channelContext, key);
}

static UA_StatusCode
setLocalSymIv_filestore(const UA_SecurityPolicy *sp,
                           void *channelContext, const UA_ByteString *iv) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->setLocalSymIv(isp, channelContext, iv);
}

static UA_StatusCode
setRemoteSymSigningKey_filestore(const UA_SecurityPolicy *sp,
                                    void *channelContext, const UA_ByteString *key) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->setRemoteSymSigningKey(isp, channelContext, key);
}

static UA_StatusCode
setRemoteSymEncryptingKey_filestore(const UA_SecurityPolicy *sp,
                                       void *channelContext, const UA_ByteString *key) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->setRemoteSymEncryptingKey(isp, channelContext, key);
}

static UA_StatusCode
setRemoteSymIv_filestore(const UA_SecurityPolicy *sp,
                            void *channelContext, const UA_ByteString *iv) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->setRemoteSymIv(isp, channelContext, iv);
}

static UA_StatusCode
generateKey_filestore(const UA_SecurityPolicy *sp,
                         void *channelContext, const UA_ByteString *secret,
                         const UA_ByteString *seed, UA_ByteString *out) {
    Filestore_Context *pc = (Filestore_Context *)sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->generateKey(isp, channelContext, secret, seed, out);
}

static UA_StatusCode
generateNonce_filestore(const UA_SecurityPolicy *sp,
                           void *channelContext, UA_ByteString *out) {
    Filestore_Context *pc = (Filestore_Context *)sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->generateNonce(isp, channelContext, out);
}

static UA_StatusCode
compareCertificate_filestore(const UA_SecurityPolicy *sp,
                                const void *channelContext,
                                const UA_ByteString *certificate) {
    Filestore_Context *pc = (Filestore_Context *)sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->compareCertificate(isp, channelContext, certificate);
}

static UA_StatusCode
updateCertificate_filestore(UA_SecurityPolicy *sp,
                            const UA_ByteString newCertificate,
                            const UA_ByteString newPrivateKey) {
    /* Temporarily save the old certificate file so that it can be removed from
     * CertStore */
    UA_ByteString localCertificateTmp;
    UA_ByteString_copy(&sp->localCertificate, &localCertificateTmp);

    Filestore_Context *pc =
        (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;

    UA_StatusCode retval = isp->updateCertificate(isp, newCertificate, newPrivateKey);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    sp->localCertificate = isp->localCertificate;

    retval = writeCertificateAndPrivateKeyToFilestore(pc->storePath,
                                                      newCertificate, newPrivateKey);
    UA_ByteString_clear(&localCertificateTmp);

    return retval;
}

static UA_StatusCode
createSigningRequest_filestore(UA_SecurityPolicy *sp,
                               const UA_String *subjectName,
                               const UA_ByteString *nonce,
                               const UA_KeyValueMap *params,
                               UA_ByteString *csr,
                               UA_ByteString *newPrivateKey) {
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->createSigningRequest(isp, subjectName, nonce, params, csr, newPrivateKey);
}

static UA_StatusCode
makeThumbprint_filestore(const UA_SecurityPolicy *securityPolicy,
                         const UA_ByteString *certificate,
                         UA_ByteString *thumbprint) {
    Filestore_Context *pc = (Filestore_Context *) securityPolicy->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->makeCertThumbprint(isp, certificate, thumbprint);
}

static UA_StatusCode
compareCertificateThumbprint_filestore(const UA_SecurityPolicy *securityPolicy,
                                       const UA_ByteString *certThumbprint) {
    Filestore_Context *pc = (Filestore_Context *) securityPolicy->policyContext;
    UA_SecurityPolicy *isp = pc->innerPolicy;
    return isp->compareCertThumbprint(isp, certThumbprint);
}

static void
clear_filestore(UA_SecurityPolicy *sp) {
    if(!sp)
        return;
    if(!sp->policyContext)
        return;

    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;

    pc->innerPolicy->clear(pc->innerPolicy);
    UA_String_clear(&pc->storePath);
    UA_free(pc->innerPolicy);
    UA_free(pc);
    sp->policyContext = NULL;
}

static UA_StatusCode
newContext_filestore(UA_SecurityPolicy *policy, const UA_String storePath) {
    if(!policy)
        return UA_STATUSCODE_BADINTERNALERROR;

    Filestore_Context *pc = (Filestore_Context *)
        UA_calloc(1, sizeof(Filestore_Context));
    if(!pc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_String_copy(&storePath, &pc->storePath);
    policy->policyContext = (void *)pc;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_SecurityPolicy_Filestore(UA_SecurityPolicy *sp,
                            UA_SecurityPolicy *innerPolicy,
                            const UA_String storePath) {
    if(!sp || !innerPolicy)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_SecurityPolicy *isp = innerPolicy;

    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = isp->logger;
    sp->policyUri = isp->policyUri;
    sp->certificateGroupId = isp->certificateGroupId;
    sp->certificateTypeId = isp->certificateTypeId;
    sp->securityLevel = isp->securityLevel;
    sp->policyType = isp->policyType;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = isp->asymSignatureAlgorithm.uri;
    asymSig->verify = asym_verify_filestore;
    asymSig->sign = asym_sign_filestore;
    asymSig->getLocalSignatureSize = asym_getLocalSignatureSize_filestore;
    asymSig->getRemoteSignatureSize = asym_getRemoteSignatureSize_filestore;
    asymSig->getLocalKeyLength = asymSig_getLocalKeyLength_filestore;
    asymSig->getRemoteKeyLength = asymSig_getRemoteKeyLength_filestore;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = isp->asymEncryptionAlgorithm.uri;
    asymEnc->encrypt = asym_encrypt_filestore; 
    asymEnc->decrypt = asym_decrypt_filestore;
    asymEnc->getLocalKeyLength = asym_getLocalKeyLength_filestore;
    asymEnc->getRemoteKeyLength = asym_getRemoteKeyLength_filestore;
    asymEnc->getRemoteBlockSize = asym_getRemoteBlockSize_filestore;
    asymEnc->getRemotePlainTextBlockSize = asym_getRemotePlainTextBlockSize_filestore;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = isp->symSignatureAlgorithm.uri;
    symSig->verify = sym_verify_filestore;
    symSig->sign = sym_sign_filestore;
    symSig->getLocalSignatureSize = sym_getLocalSignatureSize_filestore;
    symSig->getRemoteSignatureSize = sym_getRemoteSignatureSize_filestore;
    symSig->getLocalKeyLength = symSig_getLocalKeyLength_filestore;
    symSig->getRemoteKeyLength = symSig_getRemoteKeyLength_filestore;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = isp->symEncryptionAlgorithm.uri;
    symEnc->encrypt = sym_encrypt_filestore;
    symEnc->decrypt = sym_decrypt_filestore;
    symEnc->getLocalKeyLength = sym_getLocalKeyLength_filestore;
    symEnc->getRemoteKeyLength = sym_getRemoteKeyLength_filestore;
    symEnc->getRemoteBlockSize = sym_getRemoteBlockSize_filestore;
    symEnc->getRemotePlainTextBlockSize = sym_getRemotePlainTextBlockSize_filestore;

    /* Certificate Signing */
    UA_SecurityPolicySignatureAlgorithm *certSig = &sp->certSignatureAlgorithm;
    certSig->uri = isp->certSignatureAlgorithm.uri;
    certSig->verify = cert_verify_filestore;
    certSig->sign = cert_sign_filestore;
    certSig->getLocalSignatureSize = cert_getLocalSignatureSize_filestore;
    certSig->getRemoteSignatureSize = cert_getRemoteSignatureSize_filestore;
    certSig->getLocalKeyLength = cert_getLocalKeyLength_filestore;
    certSig->getRemoteKeyLength = cert_getRemoteKeyLength_filestore;

    /* Direct Method Pointers */
    sp->newChannelContext = newChannelContext_filestore;
    sp->deleteChannelContext = deleteChannelContext_filestore;
    sp->setLocalSymEncryptingKey = setLocalSymEncryptingKey_filestore;
    sp->setLocalSymSigningKey = setLocalSymSigningKey_filestore;
    sp->setLocalSymIv = setLocalSymIv_filestore;
    sp->setRemoteSymEncryptingKey = setRemoteSymEncryptingKey_filestore;
    sp->setRemoteSymSigningKey = setRemoteSymSigningKey_filestore;
    sp->setRemoteSymIv = setRemoteSymIv_filestore;
    sp->compareCertificate = compareCertificate_filestore;
    sp->generateKey = generateKey_filestore;
    sp->generateNonce = generateNonce_filestore;
    sp->nonceLength = isp->nonceLength;
    sp->makeCertThumbprint = makeThumbprint_filestore;
    sp->compareCertThumbprint = compareCertificateThumbprint_filestore;
    sp->updateCertificate = updateCertificate_filestore;
    sp->createSigningRequest = createSigningRequest_filestore;
    sp->clear = clear_filestore;

    /* Set the state / context */
    sp->localCertificate = isp->localCertificate;
    UA_StatusCode retval = newContext_filestore(sp, storePath);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the inner policy */
    Filestore_Context *pc = (Filestore_Context *) sp->policyContext;
    pc->innerPolicy = innerPolicy;

    return UA_STATUSCODE_GOOD;
}

#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */

#endif /* UA_ENABLE_ENCRYPTION */

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_common.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Kai Huebl)
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/asn1write.h>
#include <mbedtls/oid.h>
#include <mbedtls/platform.h>

#define CSR_BUFFER_SIZE 4096

void
swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB) {
    UA_ByteString tmp = *bufA;
    *bufA = *bufB;
    *bufB = tmp;
}

/* Substring search on a (not necessarily null-terminated) UA_String. */
static UA_Boolean
policyUriContains(const UA_String *uri, const char *token) {
    size_t n = strlen(token);
    if(uri->length < n)
        return false;
    for(size_t i = 0; i + n <= uri->length; i++) {
        if(memcmp(uri->data + i, token, n) == 0)
            return true;
    }
    return false;
}

/* OPC UA Part 6 v1.05.07 (SecureChannelEnhancements): hash a certificate (the
 * leaf, DER) with the hash of the policy's elliptic curve - SHA-256 for the
 * nistP256 curve, SHA-384 for nistP384. Used to build the channel-bound
 * CreateSession / ActivateSession SignatureData.
 *
 * This is NOT the OPN-header Certificate thumbprint: that thumbprint uses the
 * policy's CertificateThumbprintAlgorithm (SHA-1 by default) and is produced by
 * makeCertThumbprint. The digest here is selected from the policy URI's curve. */
UA_StatusCode
UA_SecurityPolicy_hashCertificate(const UA_SecurityPolicy *policy,
                                  const UA_ByteString *certificate,
                                  UA_ByteString *hash) {
    if(policy == NULL || certificate == NULL || hash == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Select the digest from the policy's elliptic curve, not a fixed
     * algorithm. */
    mbedtls_md_type_t mdType;
    size_t hashLen;
    if(policyUriContains(&policy->policyUri, "P384")) {
        mdType = MBEDTLS_MD_SHA384;
        hashLen = 48;
    } else if(policyUriContains(&policy->policyUri, "P256")) {
        mdType = MBEDTLS_MD_SHA256;
        hashLen = 32;
    } else {
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    }

    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(mdType);
    if(mdInfo == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_StatusCode ret = UA_ByteString_allocBuffer(hash, hashLen);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    if(mbedtls_md(mdInfo, certificate->data, certificate->length,
                  hash->data) != 0) {
        UA_ByteString_clear(hash);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

/* Backend-agnostic SecurityPolicy properties derived from the policy URI. Kept
 * out of the UA_SecurityPolicy struct (so its layout stays stable across the
 * 1.5 release family); see the #None fallback in ua_securitypolicy_none.c used
 * when no crypto backend is built. */

/* True if the policy requires the OPC UA Part 6 v1.05.07
 * SecureChannelEnhancements behavior (the ECC_nistP256_* policies). */
UA_Boolean
UA_SecurityPolicy_isEnhancedSecurity(const UA_SecurityPolicy *policy) {
    if(!policy)
        return false;
    static const UA_String eccNistP256AesGcm =
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_AesGcm");
    static const UA_String eccNistP256ChaChaPoly =
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_ChaChaPoly");
    return UA_String_equal(&policy->policyUri, &eccNistP256AesGcm) ||
           UA_String_equal(&policy->policyUri, &eccNistP256ChaChaPoly);
}

/* In the OPC UA reference stack the SequenceNumber handling depends on a
 * SecurityPolicy property `LegacySequenceNumbers`: false for all ECC policies
 * (and RSA-DH, which open62541 does not implement), true for None / RSA
 * (Basic*, Aes*_RsaOaep/RsaPss). Non-legacy starts the channel SequenceNumber
 * at 0 and wraps UA_UINT32_MAX -> 0; legacy starts at 1 with the "< 1024"
 * rollover. Detected from the policy URI (all ECC URIs carry the "ECC_"
 * fragment). A NULL policy is treated as legacy. */
UA_Boolean
UA_SecurityPolicy_useLegacySequenceNumbers(const UA_SecurityPolicy *policy) {
    if(!policy)
        return true;
    return !policyUriContains(&policy->policyUri, "ECC_");
}

UA_StatusCode
mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key,
             const UA_ByteString *in, unsigned char *out) {

    if(mbedtls_md_hmac_starts(context, key->data, key->length) != 0)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    if(mbedtls_md_hmac_update(context, in->data, in->length) != 0)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    if(mbedtls_md_hmac_finish(context, out) != 0)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_generateKey(mbedtls_md_context_t *context,
                    const UA_ByteString *secret, const UA_ByteString *seed,
                    UA_ByteString *out) {
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t hashLen = (size_t)mbedtls_md_get_size(context->md_info);
#else
    size_t hashLen = (size_t)mbedtls_md_get_size(context->private_md_info);
#endif

    UA_ByteString A_and_seed;
    UA_ByteString_allocBuffer(&A_and_seed, hashLen + seed->length);
    memcpy(A_and_seed.data + hashLen, seed->data, seed->length);

    UA_ByteString ANext_and_seed;
    UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length);
    memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length);

    UA_ByteString A = {
        hashLen,
        A_and_seed.data
    };

    UA_ByteString ANext = {
        hashLen,
        ANext_and_seed.data
    };

    UA_StatusCode retval = mbedtls_hmac(context, secret, seed, A.data);

    if(retval != UA_STATUSCODE_GOOD){
        UA_ByteString_clear(&A_and_seed);
        UA_ByteString_clear(&ANext_and_seed);
        return retval;
    }

    for(size_t offset = 0; offset < out->length; offset += hashLen) {
        UA_ByteString outSegment = {
            hashLen,
            out->data + offset
        };
        UA_Boolean bufferAllocated = UA_FALSE;
        // Not enough room in out buffer to write the hash.
        if(offset + hashLen > out->length) {
            outSegment.data = NULL;
            outSegment.length = 0;
            retval = UA_ByteString_allocBuffer(&outSegment, hashLen);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_ByteString_clear(&A_and_seed);
                UA_ByteString_clear(&ANext_and_seed);
                return retval;
            }
            bufferAllocated = UA_TRUE;
        }

        retval = mbedtls_hmac(context, secret, &A_and_seed, outSegment.data);
        if(retval != UA_STATUSCODE_GOOD){
            UA_ByteString_clear(&A_and_seed);
            UA_ByteString_clear(&ANext_and_seed);
            if(bufferAllocated)
                UA_ByteString_clear(&outSegment);
            return retval;
        }
        retval = mbedtls_hmac(context, secret, &A, ANext.data);
        if(retval != UA_STATUSCODE_GOOD){
            UA_ByteString_clear(&A_and_seed);
            UA_ByteString_clear(&ANext_and_seed);
            if(bufferAllocated)
                UA_ByteString_clear(&outSegment);
            return retval;
        }

        if(bufferAllocated) {
            memcpy(out->data + offset, outSegment.data, out->length - offset);
            UA_ByteString_clear(&outSegment);
        }

        swapBuffers(&ANext_and_seed, &A_and_seed);
        swapBuffers(&ANext, &A);
    }

    UA_ByteString_clear(&A_and_seed);
    UA_ByteString_clear(&ANext_and_seed);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message,
                       const UA_ByteString *signature) {
    /* Compute the sha1 hash */
    unsigned char hash[UA_SHA1_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_sha1_ret(message->data, message->length, hash);
#else
    mbedtls_sha1(message->data, message->length, hash);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(certificate->pk);
    if(!rsaContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);

    /* Verify */
    int mbedErr = mbedtls_pk_verify(&certificate->pk,
                                    MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH,
                                    signature->data, signature->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey,
                  mbedtls_ctr_drbg_context *drbgContext,
                  const UA_ByteString *message,
                  UA_ByteString *signature) {
    unsigned char hash[UA_SHA1_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_sha1_ret(message->data, message->length, hash);
#else
    mbedtls_sha1(message->data, message->length, hash);
#endif

    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);

    size_t sigLen = 0;
    int mbedErr = mbedtls_pk_sign(localPrivateKey, MBEDTLS_MD_SHA1, hash,
                                  UA_SHA1_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
                                  signature->length,
#endif
                                  &sigLen,
                                  mbedtls_ctr_drbg_random, drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_thumbprint_sha1(const UA_ByteString *certificate,
                        UA_ByteString *thumbprint) {
    if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL))
        return UA_STATUSCODE_BADINTERNALERROR;

    if(thumbprint->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The certificate thumbprint is always a 20 bit sha1 hash, see Part 4 of the Specification. */
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_sha1_ret(certificate->data, certificate->length, thumbprint->data);
#else
    mbedtls_sha1(certificate->data, certificate->length, thumbprint->data);
#endif
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, const size_t plainTextBlockSize) {
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t max_blocks = data->length / plainTextBlockSize;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = context->len;
#else
    size_t keylen = mbedtls_rsa_get_len(context);
#endif

    UA_ByteString encrypted;
    UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, max_blocks * keylen);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    size_t lenDataToEncrypt = data->length;
    size_t inOffset = 0;
    size_t offset = 0;
    const unsigned char *label = NULL;
    while(lenDataToEncrypt >= plainTextBlockSize) {
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
        int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random,
                                                     drbgContext, MBEDTLS_RSA_PUBLIC,
                                                     label, 0, plainTextBlockSize,
                                                     data->data + inOffset, encrypted.data + offset);
#else
        int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random,
                                                     drbgContext, label, 0, plainTextBlockSize,
                                                     data->data + inOffset, encrypted.data + offset);
#endif

        if(mbedErr) {
            UA_ByteString_clear(&encrypted);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        inOffset += plainTextBlockSize;
        offset += keylen;
        lenDataToEncrypt -= plainTextBlockSize;
    }

    memcpy(data->data, encrypted.data, offset);
    UA_ByteString_clear(&encrypted);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, int hash_id) {
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey);
    if(!rsaContext)
        return UA_STATUSCODE_BADINTERNALERROR;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, hash_id);
    size_t keylen = rsaContext->len;
#else
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, (mbedtls_md_type_t)hash_id);
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(data->length % keylen != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t inOffset = 0;
    size_t outOffset = 0;
    size_t outLength = 0;
    unsigned char buf[512];

    while(inOffset < data->length) {
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
        int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random,
                                                     drbgContext, MBEDTLS_RSA_PRIVATE,
                                                     NULL, 0, &outLength,
                                                     data->data + inOffset,
                                                     buf, 512);
#else
        int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random,
                                                     drbgContext,
                                                     NULL, 0, &outLength,
                                                     data->data + inOffset,
                                                     buf, 512);
#endif

        if(mbedErr)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

        memcpy(data->data + outOffset, buf, outLength);
        inOffset += keylen;
        outOffset += outLength;
    }

    data->length = outOffset;
    return UA_STATUSCODE_GOOD;
}

static size_t
mbedtls_getSequenceListDeep(const mbedtls_x509_sequence *sanlist) {
    size_t ret = 0;
    const mbedtls_x509_sequence *cur = sanlist;
    while(cur) {
        ret++;
        cur = cur->next;
    }

    return ret;
}

static UA_StatusCode
mbedtls_x509write_csrSetSubjectAltName(mbedtls_x509write_csr *ctx, const mbedtls_x509_sequence* sanlist) {
    int ret = 0;
    const mbedtls_x509_sequence* cur = sanlist;
    unsigned char *buf;
    unsigned char *pc;
    size_t len = 0;

    /* How many alt names to be written */
    size_t sandeep = mbedtls_getSequenceListDeep(sanlist);
    if(sandeep == 0)
        return UA_STATUSCODE_GOOD;

    size_t buflen = MBEDTLS_SAN_MAX_LEN * sandeep + sandeep;
    buf = (unsigned char *)mbedtls_calloc(1, buflen);
    if(!buf)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    memset(buf, 0, buflen);
    pc = buf + buflen;

    while(cur) {
        switch (cur->buf.tag & 0x0F) {
            case MBEDTLS_X509_SAN_DNS_NAME:
            case MBEDTLS_X509_SAN_RFC822_NAME:
            case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
            case MBEDTLS_X509_SAN_IP_ADDRESS: {
                const int writtenBytes = mbedtls_asn1_write_raw_buffer(
                    &pc, buf, (const unsigned char *)cur->buf.p, cur->buf.len);
                MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, writtenBytes);
                MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, cur->buf.len));
                MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf,
                                                                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->buf.tag));
                break;
            }
            default:
                /* Error out on an unsupported SAN */
                ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
                goto cleanup;
        }
        cur = cur->next;
    }

    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, len));
    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));

#if MBEDTLS_VERSION_NUMBER < 0x03000000
    ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_SUBJECT_ALT_NAME,
                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME), (const unsigned char*)(buf + buflen - len), len);
#else
    ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_SUBJECT_ALT_NAME,
                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME), 0, (const unsigned char*)(buf + buflen - len), len);
#endif

cleanup:
    mbedtls_free(buf);
    return (ret == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;
}

static UA_StatusCode
mbedtls_writePrivateKeyDer(mbedtls_pk_context *key, UA_ByteString *outPrivateKey) {
    unsigned char output_buf[16000];
    unsigned char *c = NULL;

    memset(output_buf, 0, 16000);
    const int len = mbedtls_pk_write_key_der(key, output_buf, 16000);
    if(len < 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    c = output_buf + sizeof(output_buf) - len;

    if(UA_ByteString_allocBuffer(outPrivateKey, (size_t)len) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    outPrivateKey->length = (size_t)len;
    memcpy(outPrivateKey->data, c, outPrivateKey->length);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_createSigningRequest(mbedtls_pk_context *localPrivateKey,
                             mbedtls_pk_context *csrLocalPrivateKey,
                             mbedtls_entropy_context *entropyContext,
                             mbedtls_ctr_drbg_context *drbgContext,
                             UA_SecurityPolicy *securityPolicy,
                             const UA_String *subjectName,
                             const UA_ByteString *nonce,
                             UA_ByteString *csr,
                             UA_ByteString *newPrivateKey) {
    /* Check parameter */
    if(!securityPolicy || !csr || !localPrivateKey || !csrLocalPrivateKey) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    int ret = 0;
    char *subj = NULL;
    const mbedtls_x509_sequence *san_list = NULL;

    mbedtls_pk_free(csrLocalPrivateKey);

    /* CSR has already been generated and private key only needs to be set
     * if a new one has been generated. */
    if(newPrivateKey && newPrivateKey->length > 0) {
        mbedtls_pk_init(csrLocalPrivateKey);

        /* Set the private key */
        if(UA_mbedTLS_LoadPrivateKey(newPrivateKey, csrLocalPrivateKey, entropyContext))
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

        return UA_STATUSCODE_GOOD;
    }

    /* CSR is already created. Nothing to do */
    if(csr && csr->length > 0)
        return UA_STATUSCODE_GOOD;

    /* Get X509 certificate */
    mbedtls_x509_crt x509Cert;
    mbedtls_x509_crt_init(&x509Cert);
    UA_ByteString certificateStr = UA_mbedTLS_CopyDataFormatAware(&securityPolicy->localCertificate);
    ret = mbedtls_x509_crt_parse(&x509Cert, certificateStr.data, certificateStr.length);
    UA_ByteString_clear(&certificateStr);
    if(ret)
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    mbedtls_x509write_csr request;
    mbedtls_x509write_csr_init(&request);
    /* Set message digest algorithms in CSR context */
    mbedtls_x509write_csr_set_md_alg(&request, MBEDTLS_MD_SHA256);

    /* Set key usage in CSR context */
    if(mbedtls_x509write_csr_set_key_usage(&request, MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
                                                     MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
                                                     MBEDTLS_X509_KU_NON_REPUDIATION |
                                                     MBEDTLS_X509_KU_KEY_ENCIPHERMENT) != 0) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Add entropy */
    UA_Boolean hasEntropy = entropyContext && nonce && nonce->length > 0;
    if(hasEntropy) {
        if(mbedtls_entropy_update_manual(entropyContext,
                                         (const unsigned char*)(nonce->data),
                                         nonce->length) != 0) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
    }

    /* Get subject from argument or read it from certificate */
    if(subjectName && subjectName->length > 0) {
        /* subject from argument */
        subj = (char *)UA_malloc(subjectName->length + 1);
        if(!subj) {
            retval = UA_STATUSCODE_BADOUTOFMEMORY;
            goto cleanup;
        }
        memset(subj, 0x00, subjectName->length + 1);
        strncpy(subj, (char *)subjectName->data, subjectName->length);
        /* search for / in subject and replace it by comma */
        char *p = subj;
        for(size_t i = 0; i < subjectName->length; i++) {
            if(*p == '/' ) {
                *p = ',';
            }
            ++p;
        }
    } else {
        /* read subject from certificate */
        mbedtls_x509_name s = x509Cert.subject;
        subj = (char *)UA_malloc(UA_MAXSUBJECTLENGTH);
        if(!subj) {
            retval = UA_STATUSCODE_BADOUTOFMEMORY;
            goto cleanup;
        }
        if(mbedtls_x509_dn_gets(subj, UA_MAXSUBJECTLENGTH, &s) <= 0) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
    }

    /* Set the subject in CSR context */
    if(mbedtls_x509write_csr_set_subject_name(&request, subj) != 0) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Get the subject alternate names from certificate and set them in CSR context*/
    san_list = &x509Cert.subject_alt_names;
    mbedtls_x509write_csrSetSubjectAltName(&request, san_list);

    /* Set private key in CSR context */
    if(newPrivateKey) {
        mbedtls_pk_init(csrLocalPrivateKey);
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
        if(mbedtls_pk_can_do(localPrivateKey, MBEDTLS_PK_ECKEY)) {
            mbedtls_pk_setup(csrLocalPrivateKey,
                             mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
            mbedtls_ecp_keypair *existingKp = mbedtls_pk_ec(*localPrivateKey);
            mbedtls_ecp_keypair *newKp = mbedtls_pk_ec(*csrLocalPrivateKey);
            if(mbedtls_ecp_gen_key(
                   existingKp->MBEDTLS_PRIVATE(grp).id,
                   newKp, mbedtls_ctr_drbg_random, drbgContext) != 0) {
                retval = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
        } else
#endif
        {
            mbedtls_pk_setup(csrLocalPrivateKey,
                             mbedtls_pk_info_from_type(MBEDTLS_PK_RSA));
            size_t keySize = 0;
            UA_CertificateUtils_getKeySize(&securityPolicy->localCertificate, &keySize);
            mbedtls_rsa_gen_key(mbedtls_pk_rsa(*csrLocalPrivateKey),
                                mbedtls_ctr_drbg_random,
                                drbgContext, (unsigned int)keySize, 65537);
        }
        mbedtls_x509write_csr_set_key(&request, csrLocalPrivateKey);
        mbedtls_writePrivateKeyDer(csrLocalPrivateKey, newPrivateKey);
    } else {
        mbedtls_x509write_csr_set_key(&request, localPrivateKey);
    }

    /* The private key associated with the request will be used for signing the
     * created CSR. For RSA keys, enforce using RSASSA-PKCS1-v1_5 scheme. */
    mbedtls_pk_context *reqKey =
#if MBEDTLS_VERSION_NUMBER < 0x03000000
        request.key;
#else
        request.private_key;
#endif
    if(mbedtls_pk_can_do(reqKey, MBEDTLS_PK_RSA)) {
        mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*reqKey);
        mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);
    }

    unsigned char requestBuf[CSR_BUFFER_SIZE];
    memset(requestBuf, 0, sizeof(requestBuf));
    ret = mbedtls_x509write_csr_der(&request, requestBuf, sizeof(requestBuf),
                                    mbedtls_ctr_drbg_random, drbgContext);
    if(ret <= 0) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* number of CSR data bytes located at the end of the request buffer */
    size_t byteCount = (size_t)ret;
    size_t offset = sizeof(requestBuf) - byteCount;

    /* copy return parameter into a ByteString */
    UA_ByteString_init(csr);
    UA_ByteString_allocBuffer(csr, byteCount);
    memcpy(csr->data, requestBuf + offset, byteCount);

cleanup:
    mbedtls_x509_crt_free(&x509Cert);
    mbedtls_x509write_csr_free(&request);
    if(subj)
        UA_free(subj);

    return retval;
}

int
UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target, void *p_rng) {
    UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(key);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    int mbedErr = mbedtls_pk_parse_key(target, data.data, data.length, NULL, 0);
#else
    int mbedErr = mbedtls_pk_parse_key(target, data.data, data.length, NULL, 0, mbedtls_entropy_func, p_rng);
#endif
    UA_ByteString_clear(&data);
    return mbedErr;
}

UA_StatusCode
UA_mbedTLS_LoadCertificate(const UA_ByteString *certificate, mbedtls_x509_crt *target) {
    const unsigned char *pData = certificate->data;

    if(certificate->length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files
        return UA_mbedTLS_LoadDerCertificate(certificate, target);
    }
    return UA_mbedTLS_LoadPemCertificate(certificate, target);
}

UA_StatusCode
UA_mbedTLS_LoadDerCertificate(const UA_ByteString *certificate, mbedtls_x509_crt *target) {
    int mbedErr = mbedtls_x509_crt_parse(target, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_mbedTLS_LoadPemCertificate(const UA_ByteString *certificate, mbedtls_x509_crt *target) {
    UA_ByteString certificateData = UA_mbedTLS_CopyDataFormatAware(certificate);
    if(!certificateData.data)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    int mbedErr = mbedtls_x509_crt_parse(target, certificateData.data, certificateData.length);
    UA_ByteString_clear(&certificateData);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_mbedTLS_LoadCrl(const UA_ByteString *crl, mbedtls_x509_crl *target) {
    const unsigned char *pData = crl->data;

    if(crl->length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files
        return UA_mbedTLS_LoadDerCrl(crl, target);
    }
    return UA_mbedTLS_LoadPemCrl(crl,target);

}

UA_StatusCode
UA_mbedTLS_LoadDerCrl(const UA_ByteString *crl, mbedtls_x509_crl *target) {
    int mbedErr = mbedtls_x509_crl_parse(target, crl->data, crl->length);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_mbedTLS_LoadPemCrl(const UA_ByteString *crl, mbedtls_x509_crl *target) {
    UA_ByteString crlData = UA_mbedTLS_CopyDataFormatAware(crl);
    if(!crlData.data)
        return UA_STATUSCODE_BADINTERNALERROR;
    int mbedErr = mbedtls_x509_crl_parse(target, crlData.data, crlData.length);
    UA_ByteString_clear(&crlData);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData,
                                UA_ByteString *target) {
    UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(certData);
    if(!data.data) {
        UA_ByteString_init(target);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);

    int mbedErr = mbedtls_x509_crt_parse(&cert, data.data, data.length);

    UA_StatusCode result = UA_STATUSCODE_BADINVALIDARGUMENT;

    if (!mbedErr) {
        UA_ByteString tmp;
        tmp.data = cert.raw.p;
        tmp.length = cert.raw.len;

        result = UA_ByteString_copy(&tmp, target);
    } else {
        UA_ByteString_init(target);
    }

    UA_ByteString_clear(&data);
    mbedtls_x509_crt_free(&cert);
    return result;
}

// mbedTLS expects PEM data to be null terminated
// The data length parameter must include the null terminator
UA_ByteString
UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data) {
    UA_ByteString result;
    UA_ByteString_init(&result);

    if (!data->length)
        return result;

    if (data->length && data->data[0] == '-') {
        UA_StatusCode res = UA_ByteString_allocBuffer(&result, data->length + 1);
        if(res != UA_STATUSCODE_GOOD)
            return result;
        memcpy(result.data, data->data, data->length);
        result.data[data->length] = '\0';
    } else {
        UA_ByteString_copy(data, &result);
    }

    return result;
}

#if MBEDTLS_VERSION_NUMBER >= 0x03000000

#include <mbedtls/ecdh.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/ecp.h>
#include <mbedtls/hkdf.h>
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>

/* ECDH shared secret computation for Weierstrass curves (NIST/Brainpool) */
static UA_StatusCode
UA_mbedTLS_ECDH(mbedtls_ecp_group_id grpId,
                mbedtls_pk_context *keyPairLocal,
                mbedtls_ctr_drbg_context *drbgContext,
                const UA_ByteString *keyPublicRemote,
                UA_ByteString *sharedSecretOut) {
    mbedtls_ecp_group grp;
    mbedtls_ecp_point Qpeer;
    mbedtls_mpi z;

    mbedtls_ecp_group_init(&grp);
    mbedtls_ecp_point_init(&Qpeer);
    mbedtls_mpi_init(&z);

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    int mbedErr;

    mbedErr = mbedtls_ecp_group_load(&grp, grpId);
    if(mbedErr != 0)
        goto errout;

    /* Import the remote public key (uncompressed point: x || y) */
    mbedErr = mbedtls_mpi_read_binary(&Qpeer.MBEDTLS_PRIVATE(X),
                                      keyPublicRemote->data,
                                      keyPublicRemote->length / 2);
    if(mbedErr != 0)
        goto errout;

    mbedErr = mbedtls_mpi_read_binary(&Qpeer.MBEDTLS_PRIVATE(Y),
                                      keyPublicRemote->data + keyPublicRemote->length / 2,
                                      keyPublicRemote->length / 2);
    if(mbedErr != 0)
        goto errout;

    mbedErr = mbedtls_mpi_lset(&Qpeer.MBEDTLS_PRIVATE(Z), 1);
    if(mbedErr != 0)
        goto errout;

    /* Get the local private key scalar d from the pk_context */
    mbedtls_ecp_keypair *kp = mbedtls_pk_ec(*keyPairLocal);
    if(kp == NULL)
        goto errout;

    /* Compute ECDH shared secret: z = d * Qpeer */
    mbedErr = mbedtls_ecdh_compute_shared(&grp, &z, &Qpeer,
                                          &kp->MBEDTLS_PRIVATE(d),
                                          mbedtls_ctr_drbg_random,
                                          drbgContext);
    if(mbedErr != 0)
        goto errout;

    /* Export shared secret to byte string */
    size_t olen = mbedtls_mpi_size(&z);
    ret = UA_ByteString_allocBuffer(sharedSecretOut, olen);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    mbedErr = mbedtls_mpi_write_binary(&z, sharedSecretOut->data,
                                       sharedSecretOut->length);
    if(mbedErr != 0) {
        UA_ByteString_clear(sharedSecretOut);
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ret = UA_STATUSCODE_GOOD;

errout:
    mbedtls_ecp_group_free(&grp);
    mbedtls_ecp_point_free(&Qpeer);
    mbedtls_mpi_free(&z);
    return ret;
}

/* Salt generation for ECC key derivation (same algorithm as OpenSSL version) */
static UA_StatusCode
UA_mbedTLS_ECC_GenerateSalt(const size_t L,
                            const UA_ByteString *label,
                            const UA_ByteString *key1,
                            const UA_ByteString *key2,
                            UA_ByteString *salt) {
    if(salt == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t saltLen = sizeof(uint16_t) + label->length + key1->length + key2->length;
    if(UA_STATUSCODE_GOOD != UA_ByteString_allocBuffer(salt, saltLen))
        return UA_STATUSCODE_BADOUTOFMEMORY;

    salt->data[0] = (UA_Byte)((L) & 0xFF);
    salt->data[1] = (UA_Byte)((L >> 8) & 0xFF);

    UA_Byte *saltPtr = &salt->data[2];
    memcpy(saltPtr, label->data, label->length);
    saltPtr += label->length;
    memcpy(saltPtr, key1->data, key1->length);
    saltPtr += key1->length;
    memcpy(saltPtr, key2->data, key2->length);

    return UA_STATUSCODE_GOOD;
}

/* HKDF key derivation */
static UA_StatusCode
UA_mbedTLS_HKDF(mbedtls_md_type_t mdType,
                const UA_ByteString *ikm,
                const UA_ByteString *salt,
                const UA_ByteString *info,
                UA_ByteString *out) {
    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(mdType);
    if(mdInfo == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    int mbedErr = mbedtls_hkdf(mdInfo,
                               salt->data, salt->length,
                               ikm->data, ikm->length,
                               info->data, info->length,
                               out->data, out->length);
    if(mbedErr != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

/* ECC key generation for Weierstrass curves */
static UA_StatusCode
UA_mbedTLS_ECC_GenerateKey(mbedtls_ecp_group_id grpId,
                           mbedtls_pk_context *keyPairOut,
                           mbedtls_ctr_drbg_context *drbgContext,
                           UA_ByteString *keyPublicEncOut) {
    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_pk_init(keyPairOut);

    int mbedErr = mbedtls_pk_setup(keyPairOut,
                                   mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
    if(mbedErr != 0)
        goto errout;

    mbedtls_ecp_keypair *kp = mbedtls_pk_ec(*keyPairOut);
    if(kp == NULL)
        goto errout;

    mbedErr = mbedtls_ecp_gen_key(grpId, kp,
                                  mbedtls_ctr_drbg_random, drbgContext);
    if(mbedErr != 0)
        goto errout;

    /* Export public key as uncompressed point (x || y) */
    {
        size_t coordLen = keyPublicEncOut->length / 2;
        mbedErr = mbedtls_mpi_write_binary(&kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X),
                                           keyPublicEncOut->data, coordLen);
        if(mbedErr != 0)
            goto errout;

        mbedErr = mbedtls_mpi_write_binary(&kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y),
                                           keyPublicEncOut->data + coordLen, coordLen);
        if(mbedErr != 0)
            goto errout;
    }

    return UA_STATUSCODE_GOOD;

errout:
    mbedtls_pk_free(keyPairOut);
    return ret;
}

/* Full ECC key derivation pipeline: ECDH → salt → HKDF */
UA_StatusCode
UA_mbedTLS_ECC_DeriveKeys(mbedtls_ecp_group_id curveID,
                          mbedtls_md_type_t hashType,
                          const UA_ApplicationType applicationType,
                          mbedtls_pk_context *localEphemeralKeyPair,
                          mbedtls_ctr_drbg_context *drbgContext,
                          const UA_ByteString *key1,
                          const UA_ByteString *key2,
                          UA_ByteString *out) {
    UA_ByteString sharedSecret = UA_BYTESTRING_NULL;
    UA_ByteString salt = UA_BYTESTRING_NULL;

    /* Get the local ephemeral public key for comparison */
    mbedtls_ecp_keypair *kp = mbedtls_pk_ec(*localEphemeralKeyPair);
    if(kp == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Export local public key as x || y for comparison */
    size_t coordLen = key1->length / 2;
    UA_ByteString localPubKey;
    UA_StatusCode ret = UA_ByteString_allocBuffer(&localPubKey, key1->length);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    int mbedErr = mbedtls_mpi_write_binary(&kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X),
                                           localPubKey.data, coordLen);
    if(mbedErr != 0) {
        UA_ByteString_clear(&localPubKey);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    mbedErr = mbedtls_mpi_write_binary(&kp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y),
                                       localPubKey.data + coordLen, coordLen);
    if(mbedErr != 0) {
        UA_ByteString_clear(&localPubKey);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Determine the label for salt generation, remote ephemeral public key for
     * ECDH, and info for HKDF */
    UA_ByteString *label = NULL;
    const UA_ByteString *remoteEphPubKey = NULL;
    static UA_String serverLabel = UA_STRING_STATIC("opcua-server");
    static UA_String clientLabel = UA_STRING_STATIC("opcua-client");
    static UA_String sessionLabel = UA_STRING_STATIC("opcua-secret");

    /* (Temporary) measure to signal salt generation for sessions */
    if(out->data[0] == 0x03 && out->data[1] == 0x03 && out->data[2] == 0x04) {
        label = &sessionLabel;
        if(applicationType == UA_APPLICATIONTYPE_SERVER) {
            remoteEphPubKey = key2;
        } else {
            remoteEphPubKey = key1;
        }
    }
    else if(memcmp(localPubKey.data, key1->data, key1->length) == 0) {
        /* Key 1 is local ephemeral public key => generating remote keys */
        remoteEphPubKey = key2;
        if(applicationType == UA_APPLICATIONTYPE_SERVER) {
            label = &clientLabel;
        } else {
            label = &serverLabel;
        }
    }
    else if(memcmp(localPubKey.data, key2->data, key2->length) == 0) {
        /* Key 2 is local ephemeral public key => generating local keys */
        remoteEphPubKey = key1;
        if(applicationType == UA_APPLICATIONTYPE_SERVER) {
            label = &serverLabel;
        } else {
            label = &clientLabel;
        }
    } else {
        UA_ByteString_clear(&localPubKey);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_ByteString_clear(&localPubKey);

    /* Use ECDH to calculate shared secret */
    ret = UA_mbedTLS_ECDH(curveID, localEphemeralKeyPair, drbgContext,
                          remoteEphPubKey, &sharedSecret);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    /* Calculate salt. The order of the (ephemeral public) keys (key1, key2) is
     * reversed because the caller sends [remote, local] for local key
     * computation and [local, remote] for remote key computation. According to
     * 6.8.1., the local salt computation appends the keys in order [local |
     * remote] and the remote salt computation [remote | local]. Therefore, no
     * additional logic is required, reversing the order is sufficient. */
    ret = UA_mbedTLS_ECC_GenerateSalt(out->length, label, key2, key1, &salt);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    /* Call HKDF to derive keys */
    /* Salt is given as the info argument (check 6.8.1., tables 66 and 67) */
    ret = UA_mbedTLS_HKDF(hashType, &sharedSecret, &salt, &salt, out);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

errout:
    UA_ByteString_clear(&sharedSecret);
    UA_ByteString_clear(&salt);
    return ret;
}

/* ECDSA sign (internal, parameterized by hash algorithm) */
static UA_StatusCode
UA_mbedTLS_ECDSA_Sign(const UA_ByteString *message,
                      mbedtls_pk_context *privateKey,
                      mbedtls_ctr_drbg_context *drbgContext,
                      mbedtls_md_type_t mdType,
                      size_t hashLen,
                      UA_ByteString *outSignature) {
    unsigned char hash[64]; /* big enough for SHA-384 (48) and SHA-256 (32) */
    unsigned char derSig[MBEDTLS_ECDSA_MAX_LEN];
    size_t derSigLen = 0;

    if(mdType == MBEDTLS_MD_SHA256) {
        mbedtls_sha256(message->data, message->length, hash, 0);
    } else if(mdType == MBEDTLS_MD_SHA384) {
        mbedtls_sha512(message->data, message->length, hash, 1);
    } else {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    int mbedErr = mbedtls_pk_sign(privateKey, mdType, hash, hashLen,
                                  derSig, sizeof(derSig), &derSigLen,
                                  mbedtls_ctr_drbg_random, drbgContext);
    if(mbedErr != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Convert DER-encoded ECDSA signature to raw (r || s) format.
     * DER format: 0x30 <len> 0x02 <r_len> <r> 0x02 <s_len> <s> */
    const unsigned char *p = derSig;
    const unsigned char *end = derSig + derSigLen;
    size_t sizeEncCoordinate = outSignature->length / 2;

    /* Skip SEQUENCE tag and length */
    if(*p != 0x30)
        return UA_STATUSCODE_BADINTERNALERROR;
    p++;
    if(*p & 0x80) p += (*p & 0x7F) + 1; /* long form length */
    else p++;

    /* Read r */
    if(p >= end || *p != 0x02)
        return UA_STATUSCODE_BADINTERNALERROR;
    p++;
    size_t rLen = *p++; 
    /* Skip leading zero padding */
    while(rLen > sizeEncCoordinate && *p == 0x00) { p++; rLen--; }
    if(rLen > sizeEncCoordinate)
        return UA_STATUSCODE_BADINTERNALERROR;
    /* Right-align r in the output */
    memset(outSignature->data, 0, sizeEncCoordinate);
    memcpy(outSignature->data + (sizeEncCoordinate - rLen), p, rLen);
    p += rLen;

    /* Read s */
    if(p >= end || *p != 0x02)
        return UA_STATUSCODE_BADINTERNALERROR;
    p++;
    size_t sLen = *p++;
    /* Skip leading zero padding */
    while(sLen > sizeEncCoordinate && *p == 0x00) { p++; sLen--; }
    if(sLen > sizeEncCoordinate)
        return UA_STATUSCODE_BADINTERNALERROR;
    /* Right-align s in the output */
    memset(outSignature->data + sizeEncCoordinate, 0, sizeEncCoordinate);
    memcpy(outSignature->data + sizeEncCoordinate + (sizeEncCoordinate - sLen), p, sLen);

    return UA_STATUSCODE_GOOD;
}

/* ECDSA verify (internal, parameterized by hash algorithm) */
static UA_StatusCode
UA_mbedTLS_ECDSA_Verify(const UA_ByteString *message,
                        mbedtls_x509_crt *publicKeyCert,
                        mbedtls_md_type_t mdType,
                        size_t hashLen,
                        const UA_ByteString *signature) {
    unsigned char hash[64];
    size_t sizeEncCoordinate = signature->length / 2;

    if(mdType == MBEDTLS_MD_SHA256) {
        mbedtls_sha256(message->data, message->length, hash, 0);
    } else if(mdType == MBEDTLS_MD_SHA384) {
        mbedtls_sha512(message->data, message->length, hash, 1);
    } else {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Convert raw (r || s) signature to DER format for mbedtls_pk_verify.
     * DER format: 0x30 <len> 0x02 <r_len> <r> 0x02 <s_len> <s>
     * Each r/s component may need a leading 0x00 if the high bit is set. */
    const unsigned char *rRaw = signature->data;
    const unsigned char *sRaw = signature->data + sizeEncCoordinate;

    /* Skip leading zeros but keep at least 1 byte */
    size_t rOff = 0;
    while(rOff < sizeEncCoordinate - 1 && rRaw[rOff] == 0x00) rOff++;
    size_t sOff = 0;
    while(sOff < sizeEncCoordinate - 1 && sRaw[sOff] == 0x00) sOff++;

    size_t rLen = sizeEncCoordinate - rOff;
    size_t sLen = sizeEncCoordinate - sOff;

    /* Add leading zero byte if high bit is set */
    int rPad = (rRaw[rOff] & 0x80) ? 1 : 0;
    int sPad = (sRaw[sOff] & 0x80) ? 1 : 0;

    size_t rDerLen = rLen + (size_t)rPad;
    size_t sDerLen = sLen + (size_t)sPad;

    /* Total DER: SEQUENCE(2 + rDerLen + 2 + sDerLen) */
    size_t innerLen = 2 + rDerLen + 2 + sDerLen;
    unsigned char derSig[MBEDTLS_ECDSA_MAX_LEN];
    unsigned char *p = derSig;

    *p++ = 0x30;
    if(innerLen >= 128) {
        *p++ = 0x81;
        *p++ = (unsigned char)innerLen;
    } else {
        *p++ = (unsigned char)innerLen;
    }

    *p++ = 0x02;
    *p++ = (unsigned char)rDerLen;
    if(rPad) *p++ = 0x00;
    memcpy(p, rRaw + rOff, rLen); p += rLen;

    *p++ = 0x02;
    *p++ = (unsigned char)sDerLen;
    if(sPad) *p++ = 0x00;
    memcpy(p, sRaw + sOff, sLen); p += sLen;

    size_t derSigLen = (size_t)(p - derSig);

    int mbedErr = mbedtls_pk_verify(&publicKeyCert->pk, mdType,
                                    hash, hashLen, derSig, derSigLen);
    if(mbedErr != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

/* Per-curve key generation wrappers */
UA_StatusCode
UA_mbedTLS_ECC_NISTP256_GenerateKey(mbedtls_pk_context *keyPairOut,
                                    mbedtls_ctr_drbg_context *drbgContext,
                                    UA_ByteString *keyPublicEncOut) {
    return UA_mbedTLS_ECC_GenerateKey(MBEDTLS_ECP_DP_SECP256R1, keyPairOut,
                                     drbgContext, keyPublicEncOut);
}

UA_StatusCode
UA_mbedTLS_ECC_NISTP384_GenerateKey(mbedtls_pk_context *keyPairOut,
                                    mbedtls_ctr_drbg_context *drbgContext,
                                    UA_ByteString *keyPublicEncOut) {
    return UA_mbedTLS_ECC_GenerateKey(MBEDTLS_ECP_DP_SECP384R1, keyPairOut,
                                     drbgContext, keyPublicEncOut);
}

UA_StatusCode
UA_mbedTLS_ECC_BRAINPOOLP256R1_GenerateKey(mbedtls_pk_context *keyPairOut,
                                           mbedtls_ctr_drbg_context *drbgContext,
                                           UA_ByteString *keyPublicEncOut) {
    return UA_mbedTLS_ECC_GenerateKey(MBEDTLS_ECP_DP_BP256R1, keyPairOut,
                                     drbgContext, keyPublicEncOut);
}

UA_StatusCode
UA_mbedTLS_ECC_BRAINPOOLP384R1_GenerateKey(mbedtls_pk_context *keyPairOut,
                                           mbedtls_ctr_drbg_context *drbgContext,
                                           UA_ByteString *keyPublicEncOut) {
    return UA_mbedTLS_ECC_GenerateKey(MBEDTLS_ECP_DP_BP384R1, keyPairOut,
                                     drbgContext, keyPublicEncOut);
}

/* ECDSA SHA-256 wrappers */
UA_StatusCode
UA_mbedTLS_ECDSA_SHA256_Sign(const UA_ByteString *message,
                             mbedtls_pk_context *privateKey,
                             mbedtls_ctr_drbg_context *drbgContext,
                             UA_ByteString *outSignature) {
    return UA_mbedTLS_ECDSA_Sign(message, privateKey, drbgContext,
                                MBEDTLS_MD_SHA256, 32, outSignature);
}

UA_StatusCode
UA_mbedTLS_ECDSA_SHA256_Verify(const UA_ByteString *message,
                               mbedtls_x509_crt *publicKeyCert,
                               const UA_ByteString *signature) {
    return UA_mbedTLS_ECDSA_Verify(message, publicKeyCert,
                                  MBEDTLS_MD_SHA256, 32, signature);
}

/* ECDSA SHA-384 wrappers */
UA_StatusCode
UA_mbedTLS_ECDSA_SHA384_Sign(const UA_ByteString *message,
                             mbedtls_pk_context *privateKey,
                             mbedtls_ctr_drbg_context *drbgContext,
                             UA_ByteString *outSignature) {
    return UA_mbedTLS_ECDSA_Sign(message, privateKey, drbgContext,
                                MBEDTLS_MD_SHA384, 48, outSignature);
}

UA_StatusCode
UA_mbedTLS_ECDSA_SHA384_Verify(const UA_ByteString *message,
                               mbedtls_x509_crt *publicKeyCert,
                               const UA_ByteString *signature) {
    return UA_mbedTLS_ECDSA_Verify(message, publicKeyCert,
                                  MBEDTLS_MD_SHA384, 48, signature);
}

/* HMAC-SHA256 sign/verify */
UA_StatusCode
UA_mbedTLS_HMAC_SHA256_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature) {
    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    unsigned char mac[32];

    int mbedErr = mbedtls_md_hmac(mdInfo, key->data, key->length,
                                  message->data, message->length, mac);
    if(mbedErr != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString macBs = {32, mac};
    if(!UA_ByteString_equal(signature, &macBs))
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_mbedTLS_HMAC_SHA256_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature) {
    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);

    int mbedErr = mbedtls_md_hmac(mdInfo, key->data, key->length,
                                  message->data, message->length,
                                  signature->data);
    if(mbedErr != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    signature->length = 32;
    return UA_STATUSCODE_GOOD;
}

/* HMAC-SHA384 sign/verify */
UA_StatusCode
UA_mbedTLS_HMAC_SHA384_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature) {
    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
    unsigned char mac[48];

    int mbedErr = mbedtls_md_hmac(mdInfo, key->data, key->length,
                                  message->data, message->length, mac);
    if(mbedErr != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString macBs = {48, mac};
    if(!UA_ByteString_equal(signature, &macBs))
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_mbedTLS_HMAC_SHA384_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature) {
    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);

    int mbedErr = mbedtls_md_hmac(mdInfo, key->data, key->length,
                                  message->data, message->length,
                                  signature->data);
    if(mbedErr != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    signature->length = 48;
    return UA_STATUSCODE_GOOD;
}

#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 */

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_basic128rsa15.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018-2019 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2018 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN 11
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH 16
#define UA_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH 16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH 128
#define UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha1MdContext;
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
} Basic128Rsa15_PolicyContext;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Basic128Rsa15_ChannelContext;

static UA_StatusCode
asym_verify_basic128rsa15(const UA_SecurityPolicy *policy, void *channelContext,
                          const UA_ByteString *message,
                          const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature);
}

static UA_StatusCode
asym_sign_basic128rsa15(const UA_SecurityPolicy *policy,
                        void *channelContext, const UA_ByteString *message,
                        UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext*)policy->policyContext;
    return mbedtls_sign_sha1(&pc->localPrivateKey, &pc->drbgContext, message, signature);
}

static size_t
asym_getLocalSignatureSize_basic128rsa15(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext*)policy->policyContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(pc->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(pc->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_basic128rsa15(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic128Rsa15_ChannelContext *cc =
        (const Basic128Rsa15_ChannelContext *)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static UA_StatusCode
asym_encrypt_basic128rsa15(const UA_SecurityPolicy *policy,
                           void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext*)policy->policyContext;

    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);

#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = remoteRsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(remoteRsaContext);
#endif
    size_t plainTextBlockSize =
        keylen - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t blocks = data->length / plainTextBlockSize;
    UA_ByteString encrypted;
    UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, blocks * keylen);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    size_t lenDataToEncrypt = data->length;
    size_t inOffset = 0;
    size_t offset = 0;
    size_t outLength = 0;
    while(lenDataToEncrypt >= plainTextBlockSize) {
        int mbedErr = mbedtls_pk_encrypt(&cc->remoteCertificate.pk,
                                         data->data + inOffset, plainTextBlockSize,
                                         encrypted.data + offset, &outLength,
                                         encrypted.length - offset,
                                         mbedtls_ctr_drbg_random,
                                         &pc->drbgContext);
        if(mbedErr) {
            UA_ByteString_clear(&encrypted);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        inOffset += plainTextBlockSize;
        offset += outLength;
        lenDataToEncrypt -= plainTextBlockSize;
    }

    memcpy(data->data, encrypted.data, offset);
    UA_ByteString_clear(&encrypted);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
asym_decrypt_basic128rsa15(const UA_SecurityPolicy *policy,
                           void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext*)policy->policyContext;

    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(data->length % keylen != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t inOffset = 0;
    size_t outOffset = 0;
    size_t outLength = 0;
    unsigned char buf[512];

    while(inOffset < data->length) {
        int mbedErr = mbedtls_pk_decrypt(&pc->localPrivateKey,
                                         data->data + inOffset, keylen,
                                         buf, &outLength, 512,
                                         mbedtls_ctr_drbg_random,
                                         &pc->drbgContext);
        if(mbedErr)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

        memcpy(data->data + outOffset, buf, outLength);
        inOffset += keylen;
        outOffset += outLength;
    }

    data->length = outOffset;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalEncryptionKeyLength_basic128rsa15(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic128Rsa15_ChannelContext *cc =
        (const Basic128Rsa15_ChannelContext *)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteEncryptionKeyLength_basic128rsa15(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    const Basic128Rsa15_ChannelContext *cc =
        (const Basic128Rsa15_ChannelContext *)channelContext;
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static size_t
asym_getRemoteBlockSize_basic128rsa15(const UA_SecurityPolicy *policy,
                                      const void *channelContext) {
    const Basic128Rsa15_ChannelContext *cc =
        (const Basic128Rsa15_ChannelContext *)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_basic128rsa15(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic128Rsa15_ChannelContext *cc =
        (const Basic128Rsa15_ChannelContext *)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
#endif
}

static UA_StatusCode
asym_makeThumbprint_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString *certificate,
                                  UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
compareCertificateThumbprint_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_verify_basic128rsa15(const UA_SecurityPolicy *policy, void *channelContext,
                         const UA_ByteString *message,
                         const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext*)policy->policyContext;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;

    unsigned char mac[UA_SHA1_LENGTH];
    if(mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey,
                    message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA1_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_basic128rsa15(const UA_SecurityPolicy *policy,
                       void *channelContext, const UA_ByteString *message,
                       UA_ByteString *signature) {
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext*)policy->policyContext;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    if(mbedtls_hmac(&pc->sha1MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_basic128rsa15(const UA_SecurityPolicy *policy,
                                   const void *channelContext) {
    return UA_SHA1_LENGTH;
}

static size_t
sym_getSigningKeyLength_basic128rsa15(const UA_SecurityPolicy *policy,
                                      const void *channelContext) {
    return UA_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_basic128rsa15(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_basic128rsa15(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_basic128rsa15(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_basic128rsa15(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_basic128rsa15(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;

    size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE;
    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext,
                                         cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_basic128rsa15(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *secret,
                              const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext *)policy->policyContext;
    return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_basic128rsa15(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext *)policy->policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                        const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    if(rsaContext->len < UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH ||
       rsaContext->len > UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
#else
    size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
    if(keylen < UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
#endif
    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_basic128rsa15(const UA_SecurityPolicy *policy,
                            void *channelContext) {
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    mbedtls_x509_crt_free(&cc->remoteCertificate);
    UA_free(cc);
}

static UA_StatusCode
newContext_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
                         const UA_ByteString *remoteCertificate,
                         void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext  == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *channelContext = UA_malloc(sizeof(Basic128Rsa15_ChannelContext));
    if(*channelContext == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)*channelContext;

    /* Initialize the channel context */
    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);
    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);
    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_basic128rsa15(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteContext_basic128rsa15(securityPolicy, cc);
        *channelContext = NULL;
    }
    return retval;
}

static UA_StatusCode
setLocalSymEncryptingKey_basic128rsa15(const UA_SecurityPolicy *policy,
                                       void *channelContext,
                                       const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
setLocalSymSigningKey_basic128rsa15(const UA_SecurityPolicy *policy,
                                       void *channelContext,
                                       const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
setLocalSymIv_basic128rsa15(const UA_SecurityPolicy *policy,
                               void *channelContext,
                               const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
setRemoteSymEncryptingKey_basic128rsa15(const UA_SecurityPolicy *policy,
                                        void *channelContext,
                                        const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
setRemoteSymSigningKey_basic128rsa15(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
setRemoteSymIv_basic128rsa15(const UA_SecurityPolicy *policy,
                             void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
compareCertificate_basic128rsa15(const UA_SecurityPolicy *policy,
                                 const void *channelContext,
                                 const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Basic128Rsa15_ChannelContext *cc =
        (const Basic128Rsa15_ChannelContext *)channelContext;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_basic128rsa15(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_md_free(&pc->sha1MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for basic128rsa15");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString newCertificate,
                                                const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_PolicyContext *pc =
        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        mbedtls_pk_free(&pc->localPrivateKey);
        mbedtls_pk_init(&pc->localPrivateKey);
        if(UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext)) {
            retval = UA_STATUSCODE_BADNOTSUPPORTED;
            goto error;
        }
    } else {
        if(!isLocalKey) {
            mbedtls_pk_free(&pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            mbedtls_pk_init(&pc->csrLocalPrivateKey);
        }
    }

    retval = asym_makeThumbprint_basic128rsa15(securityPolicy,
                                                  &securityPolicy->localCertificate,
                                                  &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_basic128rsa15(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                       const UA_String *subjectName,
                                       const UA_ByteString *nonce,
                                       const UA_KeyValueMap *params,
                                       UA_ByteString *csr,
                                       UA_ByteString *newPrivateKey) {
    /* Check parameter */
    if (securityPolicy == NULL || csr == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_PolicyContext *pc =
            (Basic128Rsa15_PolicyContext *) securityPolicy->policyContext;

    return mbedtls_createSigningRequest(&pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                        &pc->entropyContext, &pc->drbgContext,
                                        securityPolicy, subjectName, nonce,
                                        csr, newPrivateKey);
}

static UA_StatusCode
policyContext_newContext_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                       const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
        UA_malloc(sizeof(Basic128Rsa15_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Basic128Rsa15_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha1MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
    int mbedErr = mbedtls_md_setup(&pc->sha1MdContext, mdInfo, MBEDTLS_MD_SHA1);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_basic128rsa15(securityPolicy,
                                                  &securityPolicy->localCertificate,
                                                  &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_basic128rsa15(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *sp,
                                const UA_ByteString localCertificate,
                                const UA_ByteString localPrivateKey,
                                const UA_Logger *logger) {
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "!! WARNING !! The Basic128Rsa15 SecurityPolicy is unsecure. "
                   "There are known attacks that break the encryption.");

    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSAMINAPPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 0;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1");
    asymSig->verify = asym_verify_basic128rsa15;
    asymSig->sign = asym_sign_basic128rsa15;
    asymSig->getLocalSignatureSize = asym_getLocalSignatureSize_basic128rsa15;
    asymSig->getRemoteSignatureSize = asym_getRemoteSignatureSize_basic128rsa15;
    asymSig->getLocalKeyLength = NULL;
    asymSig->getRemoteKeyLength = NULL;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5");
    asymEnc->encrypt = asym_encrypt_basic128rsa15;
    asymEnc->decrypt = asym_decrypt_basic128rsa15;
    asymEnc->getLocalKeyLength = asym_getLocalEncryptionKeyLength_basic128rsa15;
    asymEnc->getRemoteKeyLength = asym_getRemoteEncryptionKeyLength_basic128rsa15;
    asymEnc->getRemoteBlockSize = asym_getRemoteBlockSize_basic128rsa15;
    asymEnc->getRemotePlainTextBlockSize = asym_getRemotePlainTextBlockSize_basic128rsa15;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    symSig->verify = sym_verify_basic128rsa15;
    symSig->sign = sym_sign_basic128rsa15;
    symSig->getLocalSignatureSize = sym_getSignatureSize_basic128rsa15;
    symSig->getRemoteSignatureSize = sym_getSignatureSize_basic128rsa15;
    symSig->getLocalKeyLength = sym_getSigningKeyLength_basic128rsa15;
    symSig->getRemoteKeyLength = sym_getSigningKeyLength_basic128rsa15;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc");
    symEnc->encrypt = sym_encrypt_basic128rsa15;
    symEnc->decrypt = sym_decrypt_basic128rsa15;
    symEnc->getLocalKeyLength = sym_getEncryptionKeyLength_basic128rsa15;
    symEnc->getRemoteKeyLength = sym_getEncryptionKeyLength_basic128rsa15;
    symEnc->getRemoteBlockSize = sym_getEncryptionBlockSize_basic128rsa15;
    symEnc->getRemotePlainTextBlockSize = sym_getPlainTextBlockSize_basic128rsa15;

    /* Certificate Signing
     * Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard). */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = newContext_basic128rsa15;
    sp->deleteChannelContext = deleteContext_basic128rsa15;
    sp->setLocalSymEncryptingKey = setLocalSymEncryptingKey_basic128rsa15;
    sp->setLocalSymSigningKey = setLocalSymSigningKey_basic128rsa15;
    sp->setLocalSymIv = setLocalSymIv_basic128rsa15;
    sp->setRemoteSymEncryptingKey = setRemoteSymEncryptingKey_basic128rsa15;
    sp->setRemoteSymSigningKey = setRemoteSymSigningKey_basic128rsa15;
    sp->setRemoteSymIv = setRemoteSymIv_basic128rsa15;
    sp->compareCertificate = compareCertificate_basic128rsa15;
    sp->generateKey = sym_generateKey_basic128rsa15;
    sp->generateNonce = sym_generateNonce_basic128rsa15;
    sp->nonceLength = 16;
    sp->makeCertThumbprint = asym_makeThumbprint_basic128rsa15;
    sp->compareCertThumbprint = compareCertificateThumbprint_basic128rsa15;
    sp->updateCertificate = updateCertificateAndPrivateKey_basic128rsa15;
    sp->createSigningRequest = createSigningRequest_basic128rsa15;
    sp->clear = clear_basic128rsa15;

    /* Load the certificate */
    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = policyContext_newContext_basic128rsa15(sp, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_basic128rsa15(sp);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_basic256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/sha1.h>
#include <mbedtls/version.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN 42
#define UA_SHA1_LENGTH 20
#define UA_BASIC256_SYM_SIGNING_KEY_LENGTH 24
#define UA_SECURITYPOLICY_BASIC256_SYM_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH 128
#define UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha1MdContext;
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
} Basic256_PolicyContext;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Basic256_ChannelContext;

/********************/
/* AsymmetricModule */
/********************/

static UA_StatusCode
asym_verify_sp_basic256(const UA_SecurityPolicy *policy, void *channelContext,
                        const UA_ByteString *message, const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature);
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_sign_sp_basic256(const UA_SecurityPolicy *policy,
                      void *channelContext, const UA_ByteString *message,
                      UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policy->policyContext;
    return mbedtls_sign_sha1(&pc->localPrivateKey, &pc->drbgContext,
                             message, signature);
}

static size_t
asym_getLocalSignatureSize_sp_basic256(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policy->policyContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(pc->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(pc->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_sp_basic256(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic256_ChannelContext *cc = (const Basic256_ChannelContext *)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_sp_basic256(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic256_ChannelContext *cc = (const Basic256_ChannelContext *)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN;
#endif
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_encrypt_sp_basic256(const UA_SecurityPolicy *policy,
                         void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Basic256_ChannelContext *cc = (const Basic256_ChannelContext *)channelContext;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policy->policyContext;
    const size_t plainTextBlockSize =
        asym_getRemotePlainTextBlockSize_sp_basic256(policy, cc);
    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &pc->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_decrypt_sp_basic256(const UA_SecurityPolicy *policy,
                         void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policy->policyContext;
    return mbedtls_decrypt_rsaOaep(&pc->localPrivateKey, &pc->drbgContext,
                                   data, MBEDTLS_MD_SHA1);
}

static size_t
asym_getLocalEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policy->policyContext;
    return mbedtls_pk_get_len(&pc->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    const Basic256_ChannelContext *cc = (const Basic256_ChannelContext *)channelContext;
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static size_t
asym_getRemoteBlockSize_sp_basic256(const UA_SecurityPolicy *policy,
                                    const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic256_ChannelContext *cc = (const Basic256_ChannelContext *)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static UA_StatusCode
asym_makeThumbprint_sp_basic256(const UA_SecurityPolicy *securityPolicy,
                                const UA_ByteString *certificate,
                                UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
compareCertificateThumbprint_sp_basic256(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Basic256_PolicyContext *pc =
        (const Basic256_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_verify_sp_basic256(const UA_SecurityPolicy *policy, void *channelContext,
                       const UA_ByteString *message,
                       const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Basic256_PolicyContext *pc =
        (Basic256_PolicyContext *)policy->policyContext;
    Basic256_ChannelContext *cc =
        (Basic256_ChannelContext *)channelContext;

    unsigned char mac[UA_SHA1_LENGTH];
    if(mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey,
                    message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA1_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_sp_basic256(const UA_SecurityPolicy *policy,
                     void *channelContext, const UA_ByteString *message,
                     UA_ByteString *signature) {
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256_PolicyContext *pc =
        (Basic256_PolicyContext *)policy->policyContext;
    Basic256_ChannelContext *cc =
        (Basic256_ChannelContext *)channelContext;

    if(mbedtls_hmac(&pc->sha1MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_sp_basic256(const UA_SecurityPolicy *policy,
                                 const void *channelContext) {
    return UA_SHA1_LENGTH;
}

static size_t
sym_getSigningKeyLength_sp_basic256(const UA_SecurityPolicy *policy,
                                    const void *channelContext) {
    return UA_BASIC256_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_sp_basic256(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_sp_basic256(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_sp_basic256(const UA_SecurityPolicy *policy,
                                      const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_sp_basic256(const UA_SecurityPolicy *policy,
                        void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Basic256_ChannelContext *cc =
        (const Basic256_ChannelContext *)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_sp_basic256(const UA_SecurityPolicy *policy,
                        void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Basic256_ChannelContext *cc =
        (const Basic256_ChannelContext *)channelContext;

    size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE;
    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext,
                                         cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_sp_basic256(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *secret,
                            const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policy->policyContext;
    return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_sp_basic256(const UA_SecurityPolicy *policy,
                              void *channelContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policy->policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_sp_basic256(Basic256_ChannelContext *cc,
                                   const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
    if(keylen < UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;

    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_sp_basic256(const UA_SecurityPolicy *policy,
                          void *channelContext) {
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    mbedtls_x509_crt_free(&cc->remoteCertificate);
    UA_free(cc);
}

static UA_StatusCode
newContext_sp_basic256(const UA_SecurityPolicy *securityPolicy,
                       const UA_ByteString *remoteCertificate,
                       void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *channelContext = UA_malloc(sizeof(Basic256_ChannelContext));
    if(*channelContext == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)*channelContext;

    /* Initialize the channel context */
    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);
    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);
    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before
    // parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_sp_basic256(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteContext_sp_basic256(securityPolicy, cc);
        *channelContext = NULL;
    }
    return retval;
}

static UA_StatusCode
setLocalSymEncryptingKey_sp_basic256(const UA_SecurityPolicy *policy,
                                     void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
setLocalSymSigningKey_sp_basic256(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
setLocalSymIv_sp_basic256(const UA_SecurityPolicy *policy,
                          void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
setRemoteSymEncryptingKey_sp_basic256(const UA_SecurityPolicy *policy,
                                      void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
setRemoteSymSigningKey_sp_basic256(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
setRemoteSymIv_sp_basic256(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
compareCertificate_sp_basic256(const UA_SecurityPolicy *policy,
                               const void *channelContext,
                               const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Basic256_ChannelContext *cc = (const Basic256_ChannelContext *)channelContext;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_sp_basic256(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_md_free(&pc->sha1MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for sp_basic256");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString newCertificate,
                                           const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
        securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval =
        UA_mbedTLS_LoadLocalCertificate(&newCertificate,
                                        &securityPolicy->localCertificate);
    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        mbedtls_pk_free(&pc->localPrivateKey);
        mbedtls_pk_init(&pc->localPrivateKey);
        if(UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey,
                                     &pc->entropyContext)) {
            retval = UA_STATUSCODE_BADNOTSUPPORTED;
            goto error;
        }
    } else {
        if(!isLocalKey) {
            mbedtls_pk_free(&pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            mbedtls_pk_init(&pc->csrLocalPrivateKey);
        }
    }

    retval = asym_makeThumbprint_sp_basic256(securityPolicy,
                                             &securityPolicy->localCertificate,
                                             &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic256(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                 const UA_String *subjectName,
                                 const UA_ByteString *nonce,
                                 const UA_KeyValueMap *params,
                                 UA_ByteString *csr,
                                 UA_ByteString *newPrivateKey) {
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_PolicyContext *pc =
            (Basic256_PolicyContext *) securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                        &pc->entropyContext, &pc->drbgContext,
                                        securityPolicy, subjectName, nonce,
                                        csr, newPrivateKey);
}

static UA_StatusCode
policyContext_newContext_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                     const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
        UA_malloc(sizeof(Basic256_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Basic256_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha1MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
    int mbedErr = mbedtls_md_setup(&pc->sha1MdContext, mdInfo, MBEDTLS_MD_SHA1);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_sp_basic256(securityPolicy,
                                             &securityPolicy->localCertificate,
                                             &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic256(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Basic256(UA_SecurityPolicy *sp, const UA_ByteString localCertificate,
                           const UA_ByteString localPrivateKey, const UA_Logger *logger) {
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "!! WARNING !! The Basic256 SecurityPolicy is unsecure. "
                   "There are known attacks that break the encryption.");

    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSAMINAPPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 0;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1");
    asymSig->verify = asym_verify_sp_basic256;
    asymSig->sign = asym_sign_sp_basic256;
    asymSig->getLocalSignatureSize = asym_getLocalSignatureSize_sp_basic256;
    asymSig->getRemoteSignatureSize = asym_getRemoteSignatureSize_sp_basic256;
    asymSig->getLocalKeyLength = NULL;
    asymSig->getRemoteKeyLength = NULL;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep");
    asymEnc->encrypt = asym_encrypt_sp_basic256;
    asymEnc->decrypt = asym_decrypt_sp_basic256;
    asymEnc->getLocalKeyLength = asym_getLocalEncryptionKeyLength_sp_basic256;
    asymEnc->getRemoteKeyLength = asym_getRemoteEncryptionKeyLength_sp_basic256;
    asymEnc->getRemoteBlockSize = asym_getRemoteBlockSize_sp_basic256;
    asymEnc->getRemotePlainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_basic256;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1");
    symSig->verify = sym_verify_sp_basic256;
    symSig->sign = sym_sign_sp_basic256;
    symSig->getLocalSignatureSize = sym_getSignatureSize_sp_basic256;
    symSig->getRemoteSignatureSize = sym_getSignatureSize_sp_basic256;
    symSig->getLocalKeyLength = sym_getSigningKeyLength_sp_basic256;
    symSig->getRemoteKeyLength = sym_getSigningKeyLength_sp_basic256;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc");
    symEnc->encrypt = sym_encrypt_sp_basic256;
    symEnc->decrypt = sym_decrypt_sp_basic256;
    symEnc->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic256;
    symEnc->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic256;
    symEnc->getRemoteBlockSize = sym_getEncryptionBlockSize_sp_basic256;
    symEnc->getRemotePlainTextBlockSize = sym_getPlainTextBlockSize_sp_basic256;

    /* Certificate Signing
     * Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard). */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = newContext_sp_basic256;
    sp->deleteChannelContext = deleteContext_sp_basic256;
    sp->setLocalSymEncryptingKey = setLocalSymEncryptingKey_sp_basic256;
    sp->setLocalSymSigningKey = setLocalSymSigningKey_sp_basic256;
    sp->setLocalSymIv = setLocalSymIv_sp_basic256;
    sp->setRemoteSymEncryptingKey = setRemoteSymEncryptingKey_sp_basic256;
    sp->setRemoteSymSigningKey = setRemoteSymSigningKey_sp_basic256;
    sp->setRemoteSymIv = setRemoteSymIv_sp_basic256;
    sp->compareCertificate = compareCertificate_sp_basic256;
    sp->generateKey = sym_generateKey_sp_basic256;
    sp->generateNonce = sym_generateNonce_sp_basic256;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = asym_makeThumbprint_sp_basic256;
    sp->compareCertThumbprint = compareCertificateThumbprint_sp_basic256;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_basic256;
    sp->createSigningRequest = createSigningRequest_sp_basic256;
    sp->clear = clear_sp_basic256;

    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = policyContext_newContext_sp_basic256(sp, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_sp_basic256(sp);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_basic256sha256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2018 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42
#define UA_SHA1_LENGTH 20
#define UA_SHA256_LENGTH 32
#define UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
} Basic256Sha256_PolicyContext;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Basic256Sha256_ChannelContext;

/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_verify_basic256sha256(const UA_SecurityPolicy *policy, void *channelContext,
                          const UA_ByteString *message,
                          const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */
    /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */
    /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL,
                                                         MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
                                                         UA_SHA256_LENGTH, hash,
                                                         signature->data); */
    int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk,
                                    MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH,
                                    signature->data, signature->length);

    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_sign_basic256sha256(const UA_SecurityPolicy *policy,
                         void *channelContext, const UA_ByteString *message,
                         UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    size_t sigLen = 0;

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */
    /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */
    int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey,
                                  MBEDTLS_MD_SHA256, hash,
                                  UA_SHA256_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
                                  signature->length,
#endif
                                  &sigLen, mbedtls_ctr_drbg_random,
                                  &pc->drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalSignatureSize_basic256sha256(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(pc->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(pc->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_basic256sha256(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic256Sha256_ChannelContext *cc =
        (const Basic256Sha256_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteBlockSize_basic256sha256(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic256Sha256_ChannelContext *cc =
        (const Basic256Sha256_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_basic256sha256(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Basic256Sha256_ChannelContext *cc =
        (const Basic256Sha256_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN;
#endif
}


/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_encrypt_basic256sha256(const UA_SecurityPolicy *policy,
                            void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    const size_t plainTextBlockSize =
        asym_getRemotePlainTextBlockSize_basic256sha256(policy, cc);
    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &pc->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_decrypt_basic256sha256(const UA_SecurityPolicy *policy,
                            void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
    return mbedtls_decrypt_rsaOaep(&pc->localPrivateKey, &pc->drbgContext,
                                   data, MBEDTLS_MD_SHA1);
}

static size_t
asym_getLocalEncryptionKeyLength_basic256sha256(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
    return mbedtls_pk_get_len(&pc->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_basic256sha256(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    const Basic256Sha256_ChannelContext *cc =
        (const Basic256Sha256_ChannelContext*)channelContext;
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static UA_StatusCode
asym_makeThumbprint_basic256sha256(const UA_SecurityPolicy *securityPolicy,
                                   const UA_ByteString *certificate,
                                   UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
compareCertificateThumbprint_basic256sha256(const UA_SecurityPolicy *securityPolicy,
                                            const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_verify_basic256sha256(const UA_SecurityPolicy *policy, void *channelContext,
                          const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext *)channelContext;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;

    unsigned char mac[UA_SHA256_LENGTH];
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_basic256sha256(const UA_SecurityPolicy *policy,
                        void *channelContext, const UA_ByteString *message,
                        UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext *)channelContext;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_basic256sha256(const UA_SecurityPolicy *policy,
                                    const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static size_t
sym_getSigningKeyLength_basic256sha256(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_basic256sha256(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_basic256sha256(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_basic256sha256(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_basic256sha256(const UA_SecurityPolicy *policy,
                           void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE;

    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_basic256sha256(const UA_SecurityPolicy *policy,
                           void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;

    size_t encryptionBlockSize =
        UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE;
    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_basic256sha256(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *secret,
                               const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_basic256sha256(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc =
        (Basic256Sha256_PolicyContext *)policy->policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                      const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
    if(keylen < UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;

    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_basic256sha256(const UA_SecurityPolicy *policy,
                             void *channelContext) {
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    mbedtls_x509_crt_free(&cc->remoteCertificate);
    UA_free(cc);
}

static UA_StatusCode
newContext_basic256sha256(const UA_SecurityPolicy *securityPolicy,
                         const UA_ByteString *remoteCertificate,
                         void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *channelContext = UA_malloc(sizeof(Basic256Sha256_ChannelContext));
    if(*channelContext == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Basic256Sha256_ChannelContext *cc = (Basic256Sha256_ChannelContext *)*channelContext;

    /* Initialize the channel context */
    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);

    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);

    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_basic256sha256(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteContext_basic256sha256(securityPolicy, cc);
        *channelContext = NULL;
    }
    return retval;
}

static UA_StatusCode
setLocalSymEncryptingKey_basic256sha256(const UA_SecurityPolicy *policy,
                                        void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
setLocalSymSigningKey_basic256sha256(const UA_SecurityPolicy *policy,
                                     void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
setLocalSymIv_basic256sha256(const UA_SecurityPolicy *policy,
                             void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
setRemoteSymEncryptingKey_basic256sha256(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
setRemoteSymSigningKey_basic256sha256(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
setRemoteSymIv_basic256sha256(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_ChannelContext *cc =
        (Basic256Sha256_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
compareCertificate_basic256sha256(const UA_SecurityPolicy *policy,
                                  const void *channelContext,
                                  const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    const Basic256Sha256_ChannelContext *cc =
        (const Basic256Sha256_ChannelContext*)channelContext;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_basic256sha256(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for basic256sha256");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                              const UA_ByteString newCertificate,
                                              const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256Sha256_PolicyContext *pc =
            (Basic256Sha256_PolicyContext *) securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval =
        UA_mbedTLS_LoadLocalCertificate(&newCertificate,
                                        &securityPolicy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        mbedtls_pk_free(&pc->localPrivateKey);
        mbedtls_pk_init(&pc->localPrivateKey);
        if(UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext)) {
            retval = UA_STATUSCODE_BADNOTSUPPORTED;
            goto error;
        }
    } else {
        if(!isLocalKey) {
            mbedtls_pk_free(&pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            mbedtls_pk_init(&pc->csrLocalPrivateKey);
        }
    }

    retval = asym_makeThumbprint_basic256sha256(securityPolicy,
                                                   &securityPolicy->localCertificate,
                                                   &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_basic256sha256(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                            const UA_String *subjectName,
                                            const UA_ByteString *nonce,
                                            const UA_KeyValueMap *params,
                                            UA_ByteString *csr,
                                            UA_ByteString *newPrivateKey) {
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc =
            (Basic256Sha256_PolicyContext *) securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                        &pc->entropyContext, &pc->drbgContext,
                                        securityPolicy, subjectName, nonce,
                                        csr, newPrivateKey);
}

static UA_StatusCode
policyContext_newContext_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                        const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)
        UA_malloc(sizeof(Basic256Sha256_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Basic256Sha256_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey,
                                        &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_basic256sha256(securityPolicy,
                                                &securityPolicy->localCertificate,
                                                &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_basic256sha256(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *sp,
                                 const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey,
                                 const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSASHA256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 20;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
    asymSig->verify = asym_verify_basic256sha256;
    asymSig->sign = asym_sign_basic256sha256;
    asymSig->getLocalSignatureSize = asym_getLocalSignatureSize_basic256sha256;
    asymSig->getRemoteSignatureSize = asym_getRemoteSignatureSize_basic256sha256;
    asymSig->getLocalKeyLength = NULL;
    asymSig->getRemoteKeyLength = NULL;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep");
    asymEnc->encrypt = asym_encrypt_basic256sha256;
    asymEnc->decrypt = asym_decrypt_basic256sha256;
    asymEnc->getLocalKeyLength = asym_getLocalEncryptionKeyLength_basic256sha256;
    asymEnc->getRemoteKeyLength = asym_getRemoteEncryptionKeyLength_basic256sha256;
    asymEnc->getRemoteBlockSize = asym_getRemoteBlockSize_basic256sha256;
    asymEnc->getRemotePlainTextBlockSize = asym_getRemotePlainTextBlockSize_basic256sha256;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256");
    symSig->verify = sym_verify_basic256sha256;
    symSig->sign = sym_sign_basic256sha256;
    symSig->getLocalSignatureSize = sym_getSignatureSize_basic256sha256;
    symSig->getRemoteSignatureSize = sym_getSignatureSize_basic256sha256;
    symSig->getLocalKeyLength = sym_getSigningKeyLength_basic256sha256;
    symSig->getRemoteKeyLength = sym_getSigningKeyLength_basic256sha256;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc");
    symEnc->encrypt = sym_encrypt_basic256sha256;
    symEnc->decrypt = sym_decrypt_basic256sha256;
    symEnc->getLocalKeyLength = sym_getEncryptionKeyLength_basic256sha256;
    symEnc->getRemoteKeyLength = sym_getEncryptionKeyLength_basic256sha256;
    symEnc->getRemoteBlockSize = sym_getEncryptionBlockSize_basic256sha256;
    symEnc->getRemotePlainTextBlockSize = sym_getPlainTextBlockSize_basic256sha256;

    /* Certificate Signing
     * Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard). */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = newContext_basic256sha256;
    sp->deleteChannelContext = deleteContext_basic256sha256;
    sp->setLocalSymEncryptingKey = setLocalSymEncryptingKey_basic256sha256;
    sp->setLocalSymSigningKey = setLocalSymSigningKey_basic256sha256;
    sp->setLocalSymIv = setLocalSymIv_basic256sha256;
    sp->setRemoteSymEncryptingKey = setRemoteSymEncryptingKey_basic256sha256;
    sp->setRemoteSymSigningKey = setRemoteSymSigningKey_basic256sha256;
    sp->setRemoteSymIv = setRemoteSymIv_basic256sha256;
    sp->compareCertificate = compareCertificate_basic256sha256;
    sp->generateKey = sym_generateKey_basic256sha256;
    sp->generateNonce = sym_generateNonce_basic256sha256;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = asym_makeThumbprint_basic256sha256;
    sp->compareCertThumbprint = compareCertificateThumbprint_basic256sha256;
    sp->updateCertificate = updateCertificateAndPrivateKey_basic256sha256;
    sp->createSigningRequest = createSigningRequest_basic256sha256;
    sp->clear = clear_basic256sha256;

    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = policyContext_newContext_basic256sha256(sp, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_basic256sha256(sp);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_aes128sha256rsaoaep.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2018 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. So we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN 42
#define UA_SHA1_LENGTH 20
#define UA_SHA256_LENGTH 32
#define UA_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_KEY_LENGTH 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
} Aes128Sha256PsaOaep_PolicyContext;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Aes128Sha256PsaOaep_ChannelContext;

/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_verify_aes128sha256rsaoaep(const UA_SecurityPolicy *policy, void *channelContext,
                                const UA_ByteString *message,
                                const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    /* Set the RSA settings */
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */
    /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */
    /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL,
                                                         MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
                                                         UA_SHA256_LENGTH, hash,
                                                         signature->data); */
    int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk,
                                    MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH,
                                    signature->data, signature->length);

    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_sign_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *message,
                              UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext*)policy->policyContext;

    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    size_t sigLen = 0;

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */
    /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */
    int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey, MBEDTLS_MD_SHA256, hash,
                                  UA_SHA256_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
                                  signature->length,
#endif
                                  &sigLen, mbedtls_ctr_drbg_random,
                                  &pc->drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalSignatureSize_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext*)policy->policyContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(pc->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(pc->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes128Sha256PsaOaep_ChannelContext *cc =
        (const Aes128Sha256PsaOaep_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteBlockSize_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes128Sha256PsaOaep_ChannelContext *cc =
        (const Aes128Sha256PsaOaep_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes128Sha256PsaOaep_ChannelContext *cc =
        (const Aes128Sha256PsaOaep_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN;
#endif
}


/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_encrypt_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext*)policy->policyContext;
    const Aes128Sha256PsaOaep_ChannelContext *cc =
        (const Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    const size_t plainTextBlockSize =
        asym_getRemotePlainTextBlockSize_aes128sha256rsaoaep(policy, cc);
    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &pc->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_decrypt_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext*)policy->policyContext;
    return mbedtls_decrypt_rsaOaep(&pc->localPrivateKey, &pc->drbgContext,
                                   data, MBEDTLS_MD_SHA1);
}

static size_t
asym_getLocalEncryptionKeyLength_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    const Aes128Sha256PsaOaep_PolicyContext *pc =
        (const Aes128Sha256PsaOaep_PolicyContext*)policy->policyContext;
    return mbedtls_pk_get_len(&pc->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                                      const void *channelContext) {
    const Aes128Sha256PsaOaep_ChannelContext *cc =
        (const Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static UA_StatusCode
makeThumbprint_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy,
                                   const UA_ByteString *certificate,
                                   UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
compareCertificateThumbprint_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_verify_aes128sha256rsaoaep(const UA_SecurityPolicy *policy, void *channelContext,
                               const UA_ByteString *message,
                               const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext *)policy->policyContext;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    unsigned char mac[UA_SHA256_LENGTH];
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey,
                    message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                             void *channelContext, const UA_ByteString *message,
                             UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext *)policy->policyContext;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static size_t
sym_getSigningKeyLength_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE;

    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;

    size_t encryptionBlockSize =
        UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE;

    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                    void *channelContext, const UA_ByteString *secret,
                                    const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext *)policy->policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                      void *channelContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext *)policy->policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                              const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(keylen < UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                  void *channelContext) {
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    mbedtls_x509_crt_free(&cc->remoteCertificate);
    UA_free(cc);
}

static UA_StatusCode
newContext_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy,
                               const UA_ByteString *remoteCertificate,
                               void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *channelContext = UA_malloc(sizeof(Aes128Sha256PsaOaep_ChannelContext));
    if(*channelContext == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext *)*channelContext;

    /* Initialize the channel context */
    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);
    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);
    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before
    // parsing the certificate
    UA_StatusCode retval =
        parseRemoteCertificate_aes128sha256rsaoaep(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteContext_aes128sha256rsaoaep(securityPolicy, cc);
        *channelContext = NULL;
    }
    return retval;
}

static UA_StatusCode
setLocalSymEncryptingKey_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                             void *channelContext,
                                             const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
setLocalSymSigningKey_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
setLocalSymIv_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
setRemoteSymEncryptingKey_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                              void *channelContext,
                                              const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
setRemoteSymSigningKey_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                           void *channelContext,
                                           const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
setRemoteSymIv_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_ChannelContext *cc =
        (Aes128Sha256PsaOaep_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
compareCertificate_aes128sha256rsaoaep(const UA_SecurityPolicy *policy,
                                       const void *channelContext,
                                       const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    const Aes128Sha256PsaOaep_ChannelContext *cc =
        (const Aes128Sha256PsaOaep_ChannelContext*)channelContext;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for aes128sha256rsaoaep");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                                   const UA_ByteString newCertificate,
                                                   const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes128Sha256PsaOaep_PolicyContext *pc =
            (Aes128Sha256PsaOaep_PolicyContext *) securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        mbedtls_pk_free(&pc->localPrivateKey);
        mbedtls_pk_init(&pc->localPrivateKey);
        if(UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext)) {
            retval = UA_STATUSCODE_BADNOTSUPPORTED;
            goto error;
        }
    } else {
        if(!isLocalKey) {
            mbedtls_pk_free(&pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            mbedtls_pk_init(&pc->csrLocalPrivateKey);
        }
    }

    retval = makeThumbprint_aes128sha256rsaoaep(securityPolicy,
                                                &securityPolicy->localCertificate,
                                                &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_aes128sha256rsaoaep(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                         const UA_String *subjectName,
                                         const UA_ByteString *nonce,
                                         const UA_KeyValueMap *params,
                                         UA_ByteString *csr,
                                         UA_ByteString *newPrivateKey) {
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
            (Aes128Sha256PsaOaep_PolicyContext *) securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                        &pc->entropyContext, &pc->drbgContext,
                                        securityPolicy, subjectName, nonce,
                                        csr, newPrivateKey);
}

static UA_StatusCode
policyContext_newContext_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                             const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)
        UA_malloc(sizeof(Aes128Sha256PsaOaep_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Aes128Sha256PsaOaep_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = makeThumbprint_aes128sha256rsaoaep(securityPolicy,
                                                &securityPolicy->localCertificate,
                                                &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_aes128sha256rsaoaep(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Aes128Sha256RsaOaep(UA_SecurityPolicy *sp,
                                      const UA_ByteString localCertificate,
                                      const UA_ByteString localPrivateKey,
                                      const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
    sp->certificateGroupId = UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSASHA256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
    asymSig->verify = asym_verify_aes128sha256rsaoaep;
    asymSig->sign = asym_sign_aes128sha256rsaoaep;
    asymSig->getLocalSignatureSize = asym_getLocalSignatureSize_aes128sha256rsaoaep;
    asymSig->getRemoteSignatureSize = asym_getRemoteSignatureSize_aes128sha256rsaoaep;
    asymSig->getLocalKeyLength = NULL;
    asymSig->getRemoteKeyLength = NULL;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep");
    asymEnc->encrypt = asym_encrypt_aes128sha256rsaoaep;
    asymEnc->decrypt = asym_decrypt_aes128sha256rsaoaep;
    asymEnc->getLocalKeyLength = asym_getLocalEncryptionKeyLength_aes128sha256rsaoaep;
    asymEnc->getRemoteKeyLength = asym_getRemoteEncryptionKeyLength_aes128sha256rsaoaep;
    asymEnc->getRemoteBlockSize = asym_getRemoteBlockSize_aes128sha256rsaoaep;
    asymEnc->getRemotePlainTextBlockSize = asym_getRemotePlainTextBlockSize_aes128sha256rsaoaep;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1");
    symSig->verify = sym_verify_aes128sha256rsaoaep;
    symSig->sign = sym_sign_aes128sha256rsaoaep;
    symSig->getLocalSignatureSize = sym_getSignatureSize_aes128sha256rsaoaep;
    symSig->getRemoteSignatureSize = sym_getSignatureSize_aes128sha256rsaoaep;
    symSig->getLocalKeyLength = sym_getSigningKeyLength_aes128sha256rsaoaep;
    symSig->getRemoteKeyLength = sym_getSigningKeyLength_aes128sha256rsaoaep;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc");
    symEnc->encrypt = sym_encrypt_aes128sha256rsaoaep;
    symEnc->decrypt = sym_decrypt_aes128sha256rsaoaep;
    symEnc->getLocalKeyLength = sym_getEncryptionKeyLength_aes128sha256rsaoaep;
    symEnc->getRemoteKeyLength = sym_getEncryptionKeyLength_aes128sha256rsaoaep;
    symEnc->getRemoteBlockSize = sym_getEncryptionBlockSize_aes128sha256rsaoaep;
    symEnc->getRemotePlainTextBlockSize = sym_getPlainTextBlockSize_aes128sha256rsaoaep;

    /* Certificate Signing
     * Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard). */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = newContext_aes128sha256rsaoaep;
    sp->deleteChannelContext = deleteContext_aes128sha256rsaoaep;
    sp->setLocalSymEncryptingKey = setLocalSymEncryptingKey_aes128sha256rsaoaep;
    sp->setLocalSymSigningKey = setLocalSymSigningKey_aes128sha256rsaoaep;
    sp->setLocalSymIv = setLocalSymIv_aes128sha256rsaoaep;
    sp->setRemoteSymEncryptingKey = setRemoteSymEncryptingKey_aes128sha256rsaoaep;
    sp->setRemoteSymSigningKey = setRemoteSymSigningKey_aes128sha256rsaoaep;
    sp->setRemoteSymIv = setRemoteSymIv_aes128sha256rsaoaep;
    sp->compareCertificate = compareCertificate_aes128sha256rsaoaep;
    sp->generateKey = sym_generateKey_aes128sha256rsaoaep;
    sp->generateNonce = sym_generateNonce_aes128sha256rsaoaep;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = makeThumbprint_aes128sha256rsaoaep;
    sp->compareCertThumbprint = compareCertificateThumbprint_aes128sha256rsaoaep;
    sp->updateCertificate = updateCertificateAndPrivateKey_aes128sha256rsaoaep;
    sp->createSigningRequest = createSigningRequest_aes128sha256rsaoaep;
    sp->clear = clear_aes128sha256rsaoaep;

    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = policyContext_newContext_aes128sha256rsaoaep(sp, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_aes128sha256rsaoaep(sp);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_aes256sha256rsapss.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Noel Graf)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. So we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SHA1_LENGTH 20
#define UA_SHA256_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN 66 /* UA_SHA256_LENGTH * 2 + 2 */
#define UA_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_KEY_LENGTH 32 /*16*/
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
} Aes256Sha256RsaPss_PolicyContext;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Aes256Sha256RsaPss_ChannelContext;

/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_verify_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                               void *channelContext,
                               const UA_ByteString *message,
                               const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);

#if MBEDTLS_VERSION_NUMBER < 0x03000000
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        policy->policyContext;
    int mbedErr =
        mbedtls_rsa_pkcs1_verify(rsaContext, mbedtls_ctr_drbg_random, &pc->drbgContext,
                                 MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
                                 UA_SHA256_LENGTH, hash, signature->data);
#else
    int mbedErr = mbedtls_rsa_pkcs1_verify(rsaContext, MBEDTLS_MD_SHA256,
                                           UA_SHA256_LENGTH, hash, signature->data);
#endif
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PSS-SHA2-256 */
static UA_StatusCode
asym_sign_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                             void *channelContext, const UA_ByteString *message,
                             UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Aes256Sha256RsaPss_PolicyContext *pc =
        (Aes256Sha256RsaPss_PolicyContext *)policy->policyContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);

#if MBEDTLS_VERSION_NUMBER < 0x03000000
    int mbedErr =
        mbedtls_rsa_pkcs1_sign(rsaContext, mbedtls_ctr_drbg_random, &pc->drbgContext,
                               MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256,
                               UA_SHA256_LENGTH, hash, signature->data);
#else
    int mbedErr = mbedtls_rsa_pkcs1_sign(rsaContext, mbedtls_ctr_drbg_random,
                                         &pc->drbgContext, MBEDTLS_MD_SHA256,
                                         UA_SHA256_LENGTH, hash, signature->data);
#endif
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalSignatureSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes256Sha256RsaPss_PolicyContext *pc =
        (const Aes256Sha256RsaPss_PolicyContext *)policy->policyContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(pc->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(pc->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes256Sha256RsaPss_ChannelContext *cc =
        (const Aes256Sha256RsaPss_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteBlockSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes256Sha256RsaPss_ChannelContext *cc =
        (const Aes256Sha256RsaPss_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes256Sha256RsaPss_ChannelContext *cc =
        (const Aes256Sha256RsaPss_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN;
#endif
}


/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA2 */
static UA_StatusCode
asym_encrypt_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        policy->policyContext;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    const size_t plainTextBlockSize =
        asym_getRemotePlainTextBlockSize_aes256sha256rsapss(policy, cc);
    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &pc->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA2 */
static UA_StatusCode
asym_decrypt_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc =
        (Aes256Sha256RsaPss_PolicyContext *)policy->policyContext;
    return mbedtls_decrypt_rsaOaep(&pc->localPrivateKey, &pc->drbgContext,
                                   data, MBEDTLS_MD_SHA256);
}

static size_t
asym_getLocalEncryptionKeyLength_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    const Aes256Sha256RsaPss_PolicyContext *pc =
        (const Aes256Sha256RsaPss_PolicyContext *)policy->policyContext;
    return mbedtls_pk_get_len(&pc->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    const Aes256Sha256RsaPss_ChannelContext *cc =
        (const Aes256Sha256RsaPss_ChannelContext*)channelContext;
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static UA_StatusCode
makeThumbprint_aes256sha256rsapss(const UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString *certificate,
                                  UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
compareCertificateThumbprint_aes256sha256rsapss(const UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc =
        (Aes256Sha256RsaPss_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_verify_aes256sha256rsapss(const UA_SecurityPolicy *policy, void *channelContext,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        policy->policyContext;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    unsigned char mac[UA_SHA256_LENGTH];
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        policy->policyContext;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static size_t
sym_getSigningKeyLength_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                               void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize =
        UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                               void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t encryptionBlockSize =
        UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE;

    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;

    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext,
                                         cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *secret,
                                   const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        policy->policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                     void *channelContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc =
        (Aes256Sha256RsaPss_PolicyContext *)policy->policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
asym_cert_verify_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                    void *channelContext,
                                    const UA_ByteString *message,
                                    const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */
    /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */
    /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL,
                                                         MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
                                                         UA_SHA256_LENGTH, hash,
                                                         signature->data); */
    int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk,
                                    MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH,
                                    signature->data, signature->length);

    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_cert_sign_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *message,
                                  UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        policy->policyContext;

    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    size_t sigLen = 0;

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */
    /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */
    int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey,
                                  MBEDTLS_MD_SHA256, hash,
                                  UA_SHA256_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
        signature->length,
#endif
                                  &sigLen, mbedtls_ctr_drbg_random,
                                  &pc->drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_cert_getLocalSignatureSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes256Sha256RsaPss_PolicyContext *pc =
        (const Aes256Sha256RsaPss_PolicyContext *) policy->policyContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(pc->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(pc->localPrivateKey));
#endif
}

static size_t
asym_cert_getRemoteSignatureSize_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    if(channelContext == NULL)
        return 0;
    const Aes256Sha256RsaPss_ChannelContext *cc =
        (const Aes256Sha256RsaPss_ChannelContext*)channelContext;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                          const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(keylen < UA_SECURITYPOLICY_AES256SHA256RSAPSS_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_AES256SHA256RSAPSS_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                 void *channelContext) {
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    mbedtls_x509_crt_free(&cc->remoteCertificate);
    UA_free(cc);
}

static UA_StatusCode
newContext_aes256sha256rsapss(const UA_SecurityPolicy *securityPolicy,
                              const UA_ByteString *remoteCertificate,
                              void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *channelContext = UA_malloc(sizeof(Aes256Sha256RsaPss_ChannelContext));
    if(*channelContext == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext *)*channelContext;

    /* Initialize the channel context */
    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);
    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);
    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before
    // parsing the certificate
    UA_StatusCode retval =
        parseRemoteCertificate_aes256sha256rsapss(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteContext_aes256sha256rsapss(securityPolicy, cc);
        *channelContext = NULL;
    }
    return retval;
}

static UA_StatusCode
setLocalSymEncryptingKey_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                            void *channelContext,
                                            const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
setLocalSymSigningKey_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
setLocalSymIv_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                 void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
setRemoteSymEncryptingKey_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                             void *channelContext,
                                             const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
setRemoteSymSigningKey_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
setRemoteSymIv_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                  void *channelContext,
                                  const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_ChannelContext *cc =
        (Aes256Sha256RsaPss_ChannelContext*)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
compareCertificate_aes256sha256rsapss(const UA_SecurityPolicy *policy,
                                      const void *channelContext,
                                      const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    const Aes256Sha256RsaPss_ChannelContext *cc =
        (const Aes256Sha256RsaPss_ChannelContext*)channelContext;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_aes256sha256rsapss(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for aes256sha256rsapss");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_aes256sha256rsapss(UA_SecurityPolicy *securityPolicy,
                                                  const UA_ByteString newCertificate,
                                                  const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes256Sha256RsaPss_PolicyContext *pc =
        (Aes256Sha256RsaPss_PolicyContext*)securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval =
        UA_mbedTLS_LoadLocalCertificate(&newCertificate,
                                        &securityPolicy->localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        mbedtls_pk_free(&pc->localPrivateKey);
        mbedtls_pk_init(&pc->localPrivateKey);
        if(UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext)) {
            retval = UA_STATUSCODE_BADNOTSUPPORTED;
            goto error;
        }
    } else {
        if(!isLocalKey) {
            mbedtls_pk_free(&pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            mbedtls_pk_init(&pc->csrLocalPrivateKey);
        }
    }

    retval = makeThumbprint_aes256sha256rsapss(securityPolicy,
                                               &securityPolicy->localCertificate,
                                               &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_aes256sha256rsapss(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_aes256sha256rsapss(UA_SecurityPolicy *securityPolicy,
                                        const UA_String *subjectName,
                                        const UA_ByteString *nonce,
                                        const UA_KeyValueMap *params,
                                        UA_ByteString *csr,
                                        UA_ByteString *newPrivateKey) {
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc =
            (Aes256Sha256RsaPss_PolicyContext *)securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                        &pc->entropyContext, &pc->drbgContext,
                                        securityPolicy, subjectName, nonce,
                                        csr, newPrivateKey);
}

static UA_StatusCode
policyContext_newContext_aes256sha256rsapss(UA_SecurityPolicy *securityPolicy,
                                            const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        UA_malloc(sizeof(Aes256Sha256RsaPss_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Aes256Sha256RsaPss_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = makeThumbprint_aes256sha256rsapss(securityPolicy,
                                               &securityPolicy->localCertificate,
                                               &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_aes256sha256rsapss(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Aes256Sha256RsaPss(UA_SecurityPolicy *sp,
                                     const UA_ByteString localCertificate,
                                     const UA_ByteString localPrivateKey,
                                     const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSASHA256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 30;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://opcfoundation.org/UA/security/rsa-pss-sha2-256");
    asymSig->verify = asym_verify_aes256sha256rsapss;
    asymSig->sign = asym_sign_aes256sha256rsapss;
    asymSig->getLocalSignatureSize = asym_getLocalSignatureSize_aes256sha256rsapss;
    asymSig->getRemoteSignatureSize = asym_getRemoteSignatureSize_aes256sha256rsapss;
    asymSig->getLocalKeyLength = NULL;
    asymSig->getRemoteKeyLength = NULL;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://opcfoundation.org/UA/security/rsa-oaep-sha2-256");
    asymEnc->encrypt = asym_encrypt_aes256sha256rsapss;
    asymEnc->decrypt = asym_decrypt_aes256sha256rsapss;
    asymEnc->getLocalKeyLength = asym_getLocalEncryptionKeyLength_aes256sha256rsapss;
    asymEnc->getRemoteKeyLength = asym_getRemoteEncryptionKeyLength_aes256sha256rsapss;
    asymEnc->getRemoteBlockSize = asym_getRemoteBlockSize_aes256sha256rsapss;
    asymEnc->getRemotePlainTextBlockSize = asym_getRemotePlainTextBlockSize_aes256sha256rsapss;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256");
    symSig->verify = sym_verify_aes256sha256rsapss;
    symSig->sign = sym_sign_aes256sha256rsapss;
    symSig->getLocalSignatureSize = sym_getSignatureSize_aes256sha256rsapss;
    symSig->getRemoteSignatureSize = sym_getSignatureSize_aes256sha256rsapss;
    symSig->getLocalKeyLength = sym_getSigningKeyLength_aes256sha256rsapss;
    symSig->getRemoteKeyLength = sym_getSigningKeyLength_aes256sha256rsapss;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = sym_encrypt_aes256sha256rsapss;
    symEnc->decrypt = sym_decrypt_aes256sha256rsapss;
    symEnc->getLocalKeyLength = sym_getEncryptionKeyLength_aes256sha256rsapss;
    symEnc->getRemoteKeyLength = sym_getEncryptionKeyLength_aes256sha256rsapss;
    symEnc->getRemoteBlockSize = sym_getEncryptionBlockSize_aes256sha256rsapss;
    symEnc->getRemotePlainTextBlockSize = sym_getPlainTextBlockSize_aes256sha256rsapss;

    /* Certificate Signing */
    UA_SecurityPolicySignatureAlgorithm *certSig = &sp->certSignatureAlgorithm;
    certSig->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
    certSig->verify = asym_cert_verify_aes256sha256rsapss;
    certSig->sign = asym_cert_sign_aes256sha256rsapss;
    certSig->getLocalSignatureSize = asym_cert_getLocalSignatureSize_aes256sha256rsapss;
    certSig->getRemoteSignatureSize = asym_cert_getRemoteSignatureSize_aes256sha256rsapss;
    certSig->getLocalKeyLength = NULL;
    certSig->getRemoteKeyLength = NULL;

    /* Direct Method Pointers */
    sp->newChannelContext = newContext_aes256sha256rsapss;
    sp->deleteChannelContext = deleteContext_aes256sha256rsapss;
    sp->setLocalSymEncryptingKey = setLocalSymEncryptingKey_aes256sha256rsapss;
    sp->setLocalSymSigningKey = setLocalSymSigningKey_aes256sha256rsapss;
    sp->setLocalSymIv = setLocalSymIv_aes256sha256rsapss;
    sp->setRemoteSymEncryptingKey = setRemoteSymEncryptingKey_aes256sha256rsapss;
    sp->setRemoteSymSigningKey = setRemoteSymSigningKey_aes256sha256rsapss;
    sp->setRemoteSymIv = setRemoteSymIv_aes256sha256rsapss;
    sp->compareCertificate = compareCertificate_aes256sha256rsapss;
    sp->generateKey = sym_generateKey_aes256sha256rsapss;
    sp->generateNonce = sym_generateNonce_aes256sha256rsapss;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = makeThumbprint_aes256sha256rsapss;
    sp->compareCertThumbprint = compareCertificateThumbprint_aes256sha256rsapss;
    sp->updateCertificate = updateCertificateAndPrivateKey_aes256sha256rsapss;
    sp->createSigningRequest = createSigningRequest_aes256sha256rsapss;
    sp->clear = clear_aes256sha256rsapss;

    UA_StatusCode res = UA_mbedTLS_LoadLocalCertificate(&localCertificate,
                                                        &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = policyContext_newContext_aes256sha256rsapss(sp, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_aes256sha256rsapss(sp);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_pubsub_aes128ctr.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Holger Zipper, ifak
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Orinigal Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SHA256_LENGTH 32
#define UA_AES128CTR_SIGNING_KEY_LENGTH 32
#define UA_AES128CTR_KEY_LENGTH 16
#define UA_AES128CTR_KEYNONCE_LENGTH 4
#define UA_AES128CTR_MESSAGENONCE_LENGTH 8
#define UA_AES128CTR_ENCRYPTION_BLOCK_SIZE 16

typedef struct {
    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
} PUBSUB_AES128CTR_PolicyContext;

typedef struct {
    UA_Byte signingKey[UA_AES128CTR_SIGNING_KEY_LENGTH];
    UA_Byte encryptingKey[UA_AES128CTR_KEY_LENGTH];
    UA_Byte keyNonce[UA_AES128CTR_KEYNONCE_LENGTH];
    UA_Byte messageNonce[UA_AES128CTR_MESSAGENONCE_LENGTH];
} PUBSUB_AES128CTR_ChannelContext;

/* Signature and verify all using HMAC-SHA2-256, nothing to change */
static UA_StatusCode
verify_pubsub_aes128ctr(const UA_PubSubSecurityPolicy *policy,
                        void *gContext, const UA_ByteString *message,
                        const UA_ByteString *signature) {
    if(gContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    PUBSUB_AES128CTR_PolicyContext *pc =
        (PUBSUB_AES128CTR_PolicyContext *)policy->policyContext;
    PUBSUB_AES128CTR_ChannelContext *gc =
        (PUBSUB_AES128CTR_ChannelContext*)gContext;

    unsigned char mac[UA_SHA256_LENGTH];
    UA_ByteString signingKey =
        {UA_AES128CTR_SIGNING_KEY_LENGTH, gc->signingKey};
    if(mbedtls_hmac(&pc->sha256MdContext, &signingKey, message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sign_pubsub_aes128ctr(const UA_PubSubSecurityPolicy *policy,
                      void *gContext, const UA_ByteString *message,
                      UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    PUBSUB_AES128CTR_PolicyContext *pc =
        (PUBSUB_AES128CTR_PolicyContext *)policy->policyContext;
    PUBSUB_AES128CTR_ChannelContext *gc =
        (PUBSUB_AES128CTR_ChannelContext*)gContext;

    UA_ByteString signingKey =
        {UA_AES128CTR_SIGNING_KEY_LENGTH, gc->signingKey};
    if(mbedtls_hmac(&pc->sha256MdContext, &signingKey, 
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

static size_t
getSignatureSize_pubsub_aes128ctr(const UA_PubSubSecurityPolicy *policy,
                                  const void *gContext) {
    return UA_SHA256_LENGTH;
}

static size_t
getSignatureKeyLength_pubsub_aes128ctr(const UA_PubSubSecurityPolicy *policy,
                                       const void *gContext) {
    return UA_AES128CTR_SIGNING_KEY_LENGTH;
}

static size_t
getEncryptionKeyLength_pubsub_aes128ctr(const UA_PubSubSecurityPolicy *policy,
                                        const void *gContext) {
    return UA_AES128CTR_KEY_LENGTH;
}

static UA_StatusCode
encrypt_pubsub_aes128ctr(const UA_PubSubSecurityPolicy *policy, void *gContext,
                         UA_ByteString *data) {
    if(gContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    PUBSUB_AES128CTR_ChannelContext *gc =
        (PUBSUB_AES128CTR_ChannelContext*)gContext;

    /* CTR mode does not need padding */

    /* Decode the header to Extract the message nonce */

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(UA_AES128CTR_KEY_LENGTH * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, gc->encryptingKey, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Prepare the counterBlock required for encryption/decryption 
     * Block counter starts at 1 according to part 14 (7.2.2.4.3.2)*/
    UA_Byte counterBlockCopy[UA_AES128CTR_ENCRYPTION_BLOCK_SIZE];
    UA_Byte counterInitialValue[4] = {0,0,0,1};
    memcpy(counterBlockCopy, gc->keyNonce, UA_AES128CTR_KEYNONCE_LENGTH);
    memcpy(counterBlockCopy + UA_AES128CTR_KEYNONCE_LENGTH,
           gc->messageNonce, UA_AES128CTR_MESSAGENONCE_LENGTH);
    memcpy(counterBlockCopy + UA_AES128CTR_KEYNONCE_LENGTH +
           UA_AES128CTR_MESSAGENONCE_LENGTH, &counterInitialValue, 4);

    size_t counterblockoffset = 0;
    UA_Byte aesBuffer[UA_AES128CTR_ENCRYPTION_BLOCK_SIZE];
    mbedErr = mbedtls_aes_crypt_ctr(&aesContext, data->length, &counterblockoffset,
                                    counterBlockCopy, aesBuffer, data->data, data->data);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

/* a decryption function is exactly the same as an encryption one, since they all do XOR
 * operations*/
static UA_StatusCode
decrypt_pubsub_aes128ctr(const UA_PubSubSecurityPolicy *policy, void *gContext,
                         UA_ByteString *data) {
    return encrypt_pubsub_aes128ctr(policy, gContext, data);
}

static UA_StatusCode
generateKey_pubsub_aes128ctr(UA_PubSubSecurityPolicy *policy,
                             void *gContext, const UA_ByteString *secret,
                             const UA_ByteString *seed, UA_ByteString *out) {
    if(policy == NULL || secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    PUBSUB_AES128CTR_PolicyContext *pc =
        (PUBSUB_AES128CTR_PolicyContext *)policy->policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

static UA_StatusCode
generateNonce_pubsub_aes128ctr(UA_PubSubSecurityPolicy *policy,
                               void *gContext, UA_ByteString *out) {
    if(policy == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    PUBSUB_AES128CTR_PolicyContext *pc =
        (PUBSUB_AES128CTR_PolicyContext *)policy->policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_pubsub_aes128ctr(UA_PubSubSecurityPolicy *policy, void *gContext) {
    UA_free(gContext);
}

static UA_StatusCode
newContext_pubsub_aes128ctr(UA_PubSubSecurityPolicy *policy,
                            const UA_ByteString *signingKey,
                            const UA_ByteString *encryptingKey,
                            const UA_ByteString *keyNonce,
                            void **gContext) {
    if((signingKey && signingKey->length != UA_AES128CTR_SIGNING_KEY_LENGTH) ||
       (encryptingKey && encryptingKey->length != UA_AES128CTR_KEY_LENGTH) ||
       (keyNonce && keyNonce->length != UA_AES128CTR_KEYNONCE_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Allocate the channel context */
    PUBSUB_AES128CTR_ChannelContext *gc = (PUBSUB_AES128CTR_ChannelContext *)
        UA_calloc(1, sizeof(PUBSUB_AES128CTR_ChannelContext));
    if(gc == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Initialize the channel context */
    if(signingKey)
        memcpy(gc->signingKey, signingKey->data, signingKey->length);
    if(encryptingKey)
        memcpy(gc->encryptingKey, encryptingKey->data, encryptingKey->length);
    if(keyNonce)
        memcpy(gc->keyNonce, keyNonce->data, keyNonce->length);
    *gContext = gc;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setKeys_pubsub_aes128ctr(UA_PubSubSecurityPolicy *policy, void *gContext,
                         const UA_ByteString *signingKey,
                         const UA_ByteString *encryptingKey,
                         const UA_ByteString *keyNonce) {
    if(!gContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(!signingKey || signingKey->length != UA_AES128CTR_SIGNING_KEY_LENGTH ||
       !encryptingKey || encryptingKey->length != UA_AES128CTR_KEY_LENGTH ||
       !keyNonce || keyNonce->length != UA_AES128CTR_KEYNONCE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    PUBSUB_AES128CTR_ChannelContext *gc =
        (PUBSUB_AES128CTR_ChannelContext*)gContext;
    memcpy(gc->signingKey, signingKey->data, signingKey->length);
    memcpy(gc->encryptingKey, encryptingKey->data, encryptingKey->length);
    memcpy(gc->keyNonce, keyNonce->data, keyNonce->length);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setMessageNonce_pubsub_aes128ctr(UA_PubSubSecurityPolicy *policy, void *gContext,
                                 const UA_ByteString *nonce) {
    if(nonce->length != UA_AES128CTR_MESSAGENONCE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    PUBSUB_AES128CTR_ChannelContext *gc =
        (PUBSUB_AES128CTR_ChannelContext*)gContext;
    memcpy(gc->messageNonce, nonce->data, nonce->length);
    return UA_STATUSCODE_GOOD;
}

static void
clear_pubsub_aes128ctr(UA_PubSubSecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;
    if(securityPolicy->policyContext == NULL)
        return;
    PUBSUB_AES128CTR_PolicyContext *pc =
        (PUBSUB_AES128CTR_PolicyContext *)securityPolicy->policyContext;
    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for PUBSUB_AES128CTR");
    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
setup_pubsub_aes128ctr(UA_PubSubSecurityPolicy *securityPolicy) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    PUBSUB_AES128CTR_PolicyContext *pc = (PUBSUB_AES128CTR_PolicyContext *)
        UA_calloc(1, sizeof(PUBSUB_AES128CTR_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext");
    if(securityPolicy->policyContext != NULL)
        clear_pubsub_aes128ctr(securityPolicy);
    return retval;
}

UA_StatusCode
UA_PubSubSecurityPolicy_Aes128Ctr(UA_PubSubSecurityPolicy *sp,
                                  const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_PubSubSecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#PubSub-Aes128-CTR");

    /* Set the method pointers */
    sp->newGroupContext = newContext_pubsub_aes128ctr;
    sp->deleteGroupContext = deleteContext_pubsub_aes128ctr;
    sp->verify = verify_pubsub_aes128ctr;
    sp->sign = sign_pubsub_aes128ctr;
    sp->getSignatureSize = getSignatureSize_pubsub_aes128ctr;
    sp->getSignatureKeyLength = getSignatureKeyLength_pubsub_aes128ctr;
    sp->getEncryptionKeyLength = getEncryptionKeyLength_pubsub_aes128ctr;
    sp->encrypt = encrypt_pubsub_aes128ctr;
    sp->decrypt = decrypt_pubsub_aes128ctr;
    sp->setSecurityKeys = setKeys_pubsub_aes128ctr;
    sp->generateKey = generateKey_pubsub_aes128ctr;
    sp->generateNonce = generateNonce_pubsub_aes128ctr;
    sp->nonceLength = UA_AES128CTR_SIGNING_KEY_LENGTH +
        UA_AES128CTR_KEY_LENGTH + UA_AES128CTR_KEYNONCE_LENGTH;
    sp->setMessageNonce = setMessageNonce_pubsub_aes128ctr;
    sp->clear = clear_pubsub_aes128ctr;

    /* Initialize the policyContext */
    return setup_pubsub_aes128ctr(sp);
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_pubsub_aes256ctr.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Holger Zipper, ifak
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Orinigal Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SHA256_LENGTH 32
#define UA_AES256CTR_SIGNING_KEY_LENGTH 32
#define UA_AES256CTR_KEY_LENGTH 32
#define UA_AES256CTR_KEYNONCE_LENGTH 4
#define UA_AES256CTR_MESSAGENONCE_LENGTH 8
#define UA_AES256CTR_ENCRYPTION_BLOCK_SIZE 16

typedef struct {
    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
} PUBSUB_AES256CTR_PolicyContext;

typedef struct {
    UA_Byte signingKey[UA_AES256CTR_SIGNING_KEY_LENGTH];
    UA_Byte encryptingKey[UA_AES256CTR_KEY_LENGTH];
    UA_Byte keyNonce[UA_AES256CTR_KEYNONCE_LENGTH];
    UA_Byte messageNonce[UA_AES256CTR_MESSAGENONCE_LENGTH];
} PUBSUB_AES256CTR_ChannelContext;

/* Signature and verify all using HMAC-SHA2-256, nothing to change */
static UA_StatusCode
verify_pubsub_aes256ctr(const UA_PubSubSecurityPolicy *policy,
                        void *gContext, const UA_ByteString *message,
                        const UA_ByteString *signature) {
    if(gContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    PUBSUB_AES256CTR_ChannelContext *gc =
        (PUBSUB_AES256CTR_ChannelContext*)gContext;
    PUBSUB_AES256CTR_PolicyContext *pc =
        (PUBSUB_AES256CTR_PolicyContext *)policy->policyContext;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    unsigned char mac[UA_SHA256_LENGTH];
    UA_ByteString signingKey =
        {UA_AES256CTR_SIGNING_KEY_LENGTH, gc->signingKey};
    if(mbedtls_hmac(&pc->sha256MdContext, &signingKey, message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sign_pubsub_aes256ctr(const UA_PubSubSecurityPolicy *policy,
                      void *gContext, const UA_ByteString *message,
                      UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;
    PUBSUB_AES256CTR_ChannelContext *gc =
        (PUBSUB_AES256CTR_ChannelContext*)gContext;
    PUBSUB_AES256CTR_PolicyContext *pc =
        (PUBSUB_AES256CTR_PolicyContext *)policy->policyContext;
    UA_ByteString signingKey =
        {UA_AES256CTR_SIGNING_KEY_LENGTH, gc->signingKey};
    if(mbedtls_hmac(&pc->sha256MdContext, &signingKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static size_t
getSignatureSize_pubsub_aes256ctr(const UA_PubSubSecurityPolicy *policy,
                                  const void *gContext) {
    return UA_SHA256_LENGTH;
}

static size_t
getSignatureKeyLength_pubsub_aes256ctr(const UA_PubSubSecurityPolicy *policy,
                                       const void *gContext) {
    return UA_AES256CTR_SIGNING_KEY_LENGTH;
}

static size_t
getEncryptionKeyLength_pubsub_aes256ctr(const UA_PubSubSecurityPolicy *policy,
                                        const void *gContext) {
    return UA_AES256CTR_KEY_LENGTH;
}

static UA_StatusCode
encrypt_pubsub_aes256ctr(const UA_PubSubSecurityPolicy *policy, void *gContext,
                         UA_ByteString *data) {
    if(gContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    PUBSUB_AES256CTR_ChannelContext *gc =
        (PUBSUB_AES256CTR_ChannelContext*)gContext;

    /* CTR mode does not need padding */

    /* Decode the header to Extract the message nonce */

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(UA_AES256CTR_KEY_LENGTH * 8);
    mbedtls_aes_context aesContext;
    int mbedErr =
        mbedtls_aes_setkey_enc(&aesContext, gc->encryptingKey, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Prepare the counterBlock required for encryption/decryption
     * Block counter starts at 1 according to part 14 (7.2.2.4.3.2)*/
    UA_Byte counterBlockCopy[UA_AES256CTR_ENCRYPTION_BLOCK_SIZE];
    UA_Byte counterInitialValue[4] = {0,0,0,1};
    memcpy(counterBlockCopy, gc->keyNonce, UA_AES256CTR_KEYNONCE_LENGTH);
    memcpy(counterBlockCopy + UA_AES256CTR_KEYNONCE_LENGTH,
           gc->messageNonce, UA_AES256CTR_MESSAGENONCE_LENGTH);
    memcpy(counterBlockCopy + UA_AES256CTR_KEYNONCE_LENGTH +
           UA_AES256CTR_MESSAGENONCE_LENGTH, &counterInitialValue, 4);

    size_t counterblockoffset = 0;
    UA_Byte aesBuffer[UA_AES256CTR_ENCRYPTION_BLOCK_SIZE];
    mbedErr = mbedtls_aes_crypt_ctr(&aesContext, data->length, &counterblockoffset,
                                    counterBlockCopy, aesBuffer, data->data, data->data);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

/* a decryption function is exactly the same as an encryption one, since they all do XOR
 * operations*/
static UA_StatusCode
decrypt_pubsub_aes256ctr(const UA_PubSubSecurityPolicy *policy, void *gContext,
                         UA_ByteString *data) {
    return encrypt_pubsub_aes256ctr(policy, gContext, data);
}

static UA_StatusCode
generateKey_pubsub_aes256ctr(UA_PubSubSecurityPolicy *policy,
                             void *gContext, const UA_ByteString *secret,
                             const UA_ByteString *seed, UA_ByteString *out) {
    if(policy == NULL || secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    PUBSUB_AES256CTR_PolicyContext *pc =
        (PUBSUB_AES256CTR_PolicyContext *)policy->policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

/* This nonce does not to be  a
cryptographically random number, it can be pseudo-random */
static UA_StatusCode
generateNonce_pubsub_aes256ctr(UA_PubSubSecurityPolicy *policy,
                               void *gContext, UA_ByteString *out) {
    if(policy == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    PUBSUB_AES256CTR_PolicyContext *pc =
        (PUBSUB_AES256CTR_PolicyContext *)policy->policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static void
deleteGroupContext_pubsub_aes256ctr(UA_PubSubSecurityPolicy *policy, void *gContext) {
    UA_free(gContext);
}

static UA_StatusCode
newGroupContext_pubsub_aes256ctr(UA_PubSubSecurityPolicy *policy,
                                 const UA_ByteString *signingKey,
                                 const UA_ByteString *encryptingKey,
                                 const UA_ByteString *keyNonce,
                                 void **gContext) {
    if((signingKey && signingKey->length != UA_AES256CTR_SIGNING_KEY_LENGTH) ||
       (encryptingKey && encryptingKey->length != UA_AES256CTR_KEY_LENGTH) ||
       (keyNonce && keyNonce->length != UA_AES256CTR_KEYNONCE_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Allocate the channel context */
    PUBSUB_AES256CTR_ChannelContext *cc = (PUBSUB_AES256CTR_ChannelContext *)
        UA_calloc(1, sizeof(PUBSUB_AES256CTR_ChannelContext));
    if(cc == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Initialize the channel context */
    if(signingKey)
        memcpy(cc->signingKey, signingKey->data, signingKey->length);
    if(encryptingKey)
        memcpy(cc->encryptingKey, encryptingKey->data, encryptingKey->length);
    if(keyNonce)
        memcpy(cc->keyNonce, keyNonce->data, keyNonce->length);
    *gContext = cc;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setKeys_pubsub_aes256ctr(UA_PubSubSecurityPolicy *policy, void *gContext,
                         const UA_ByteString *signingKey,
                         const UA_ByteString *encryptingKey,
                         const UA_ByteString *keyNonce) {
    if(!gContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(!signingKey || signingKey->length != UA_AES256CTR_SIGNING_KEY_LENGTH ||
       !encryptingKey || encryptingKey->length != UA_AES256CTR_KEY_LENGTH ||
       !keyNonce || keyNonce->length != UA_AES256CTR_KEYNONCE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    PUBSUB_AES256CTR_ChannelContext *gc =
        (PUBSUB_AES256CTR_ChannelContext*)gContext;
    memcpy(gc->signingKey, signingKey->data, signingKey->length);
    memcpy(gc->encryptingKey, encryptingKey->data, encryptingKey->length);
    memcpy(gc->keyNonce, keyNonce->data, keyNonce->length);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setMessageNonce_pubsub_aes256ctr(UA_PubSubSecurityPolicy *policy,
                                 void *gContext, const UA_ByteString *nonce) {
    if(nonce->length != UA_AES256CTR_MESSAGENONCE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    PUBSUB_AES256CTR_ChannelContext *gc =
        (PUBSUB_AES256CTR_ChannelContext*)gContext;
    memcpy(gc->messageNonce, nonce->data, nonce->length);
    return UA_STATUSCODE_GOOD;
}

static void
clear_pubsub_aes256ctr(UA_PubSubSecurityPolicy *policy) {
    if(policy == NULL || policy->policyContext == NULL)
        return;
    PUBSUB_AES256CTR_PolicyContext *pc =
        (PUBSUB_AES256CTR_PolicyContext *)policy->policyContext;
    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_free(pc);
    policy->policyContext = NULL;
}

static UA_StatusCode
setup_pubsub_aes256ctr(UA_PubSubSecurityPolicy *securityPolicy) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    PUBSUB_AES256CTR_PolicyContext *pc = (PUBSUB_AES256CTR_PolicyContext *)
        UA_calloc(1, sizeof(PUBSUB_AES256CTR_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(PUBSUB_AES256CTR_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext");
    if(securityPolicy->policyContext != NULL)
        clear_pubsub_aes256ctr(securityPolicy);
    return retval;
}

UA_StatusCode
UA_PubSubSecurityPolicy_Aes256Ctr(UA_PubSubSecurityPolicy *sp,
                                  const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_PubSubSecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#PubSub-Aes256-CTR");

    /* Set the method pointers */
    sp->newGroupContext = newGroupContext_pubsub_aes256ctr;
    sp->deleteGroupContext = deleteGroupContext_pubsub_aes256ctr;
    sp->verify = verify_pubsub_aes256ctr;
    sp->sign = sign_pubsub_aes256ctr;
    sp->getSignatureSize = getSignatureSize_pubsub_aes256ctr;
    sp->getSignatureKeyLength = getSignatureKeyLength_pubsub_aes256ctr;
    sp->getEncryptionKeyLength = getEncryptionKeyLength_pubsub_aes256ctr;
    sp->encrypt = encrypt_pubsub_aes256ctr;
    sp->decrypt = decrypt_pubsub_aes256ctr;
    sp->setSecurityKeys = setKeys_pubsub_aes256ctr;
    sp->generateKey = generateKey_pubsub_aes256ctr;
    sp->generateNonce = generateNonce_pubsub_aes256ctr;
    sp->nonceLength = UA_AES256CTR_SIGNING_KEY_LENGTH +
        UA_AES256CTR_KEY_LENGTH + UA_AES256CTR_KEYNONCE_LENGTH;
    sp->setMessageNonce = setMessageNonce_pubsub_aes256ctr;
    sp->clear = clear_pubsub_aes256ctr;

    /* Initialize the policyContext */
    return setup_pubsub_aes256ctr(sp);
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_eccnistp256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x03000000


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH 64
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH 16
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP256_NONCE_LENGTH_BYTES 64

typedef struct {
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccNistP256;

typedef struct Channel_Context_EccNistP256 {
    mbedtls_pk_context localEphemeralKeyPair;
    UA_Boolean ephemeralKeyInitialized;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    mbedtls_x509_crt remoteCertificateX509;
} Channel_Context_EccNistP256;

static UA_StatusCode
UA_Policy_EccNistP256_New_Context(UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString localPrivateKey,
                                  const UA_ApplicationType applicationType,
                                  const UA_Logger *logger) {
    Policy_Context_EccNistP256 *context = (Policy_Context_EccNistP256 *)
        UA_malloc(sizeof(Policy_Context_EccNistP256));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    mbedtls_pk_init(&context->localPrivateKey);
    mbedtls_pk_init(&context->csrLocalPrivateKey);
    mbedtls_entropy_init(&context->entropyContext);
    mbedtls_ctr_drbg_init(&context->drbgContext);

    int mbedErr = mbedtls_ctr_drbg_seed(&context->drbgContext,
                                         mbedtls_entropy_func,
                                         &context->entropyContext, NULL, 0);
    if(mbedErr) {
        UA_free(context);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &context->localPrivateKey,
                                        &context->entropyContext);
    if(mbedErr) {
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Verify the key is an EC key */
    if(!mbedtls_pk_can_do(&context->localPrivateKey, MBEDTLS_PK_ECKEY)) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval =
        UA_ByteString_allocBuffer(&context->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &context->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&context->localCertThumbprint);
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;
    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccNistP256_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)policy->policyContext;
    if(!pc)
        return;

    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccnistp256(UA_SecurityPolicy *securityPolicy,
                                    const UA_String *subjectName,
                                    const UA_ByteString *nonce,
                                    const UA_KeyValueMap *params,
                                    UA_ByteString *csr,
                                    UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256*)securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey,
                                        &pc->csrLocalPrivateKey,
                                        &pc->entropyContext,
                                        &pc->drbgContext,
                                        securityPolicy, subjectName,
                                        nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccNistP256(UA_SecurityPolicy *securityPolicy,
                                              const UA_ByteString newCertificate,
                                              const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)securityPolicy->policyContext;

    /* Set the certificate */
    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
    int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey,
                                            &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Update the thumbprint */
    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccNistP256_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccNistP256_New_Context(const UA_SecurityPolicy *securityPolicy,
                        const UA_ByteString *remoteCertificate,
                        void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP256 *newContext = (Channel_Context_EccNistP256 *)
        UA_calloc(1, sizeof(Channel_Context_EccNistP256));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_ByteString_copy(remoteCertificate, &newContext->remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    /* Decode to X509 */
    mbedtls_x509_crt_init(&newContext->remoteCertificateX509);
    retval = UA_mbedTLS_LoadCertificate(&newContext->remoteCertificate,
                                        &newContext->remoteCertificateX509);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&newContext->remoteCertificate);
        UA_free(newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    mbedtls_pk_init(&newContext->localEphemeralKeyPair);
    newContext->ephemeralKeyInitialized = UA_FALSE;

    *channelContext = newContext;
    return UA_STATUSCODE_GOOD;
}

static void
EccNistP256_Delete_Context(const UA_SecurityPolicy *policy,
                           void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccNistP256 *cc =
        (Channel_Context_EccNistP256 *)channelContext;
    mbedtls_x509_crt_free(&cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    if(cc->ephemeralKeyInitialized)
        mbedtls_pk_free(&cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccNistP256(const UA_SecurityPolicy *policy,
                                            const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccNistP256(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *certificate,
                                         UA_ByteString *thumbprint) {
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static size_t
UA_Asym_EccNistP256_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccNistP256_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccNistP256_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    /* No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

static UA_StatusCode
UA_Sym_EccNistP256_generateNonce(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *out) {
    Policy_Context_EccNistP256 *pctx =
        (Policy_Context_EccNistP256*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Detect if we want to create an ephemeral key or just cryptographic random
     * data */
    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccNistP256 *cctx = (Channel_Context_EccNistP256*)channelContext;
        if(cctx->ephemeralKeyInitialized)
            mbedtls_pk_free(&cctx->localEphemeralKeyPair);
        UA_StatusCode res = UA_mbedTLS_ECC_NISTP256_GenerateKey(
            &cctx->localEphemeralKeyPair, &pctx->drbgContext, out);
        if(res == UA_STATUSCODE_GOOD)
            cctx->ephemeralKeyInitialized = UA_TRUE;
        return res;
    }

    int rc = mbedtls_ctr_drbg_random(&pctx->drbgContext, out->data, out->length);
    return (rc == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccNistP256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccNistP256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccNistP256_generateKey(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *secret,
                               const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccNistP256 *pctx =
        (Policy_Context_EccNistP256 *)policy->policyContext;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_mbedTLS_ECC_DeriveKeys(MBEDTLS_ECP_DP_SECP256R1, MBEDTLS_MD_SHA256,
                                     pctx->applicationType,
                                     &cc->localEphemeralKeyPair,
                                     &pctx->drbgContext,
                                     secret, seed, out);
}

static UA_StatusCode
EccNistP256_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                  void *channelContext,
                                  const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccNistP256_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccNistP256_setLocalSymIv(const UA_SecurityPolicy *policy,
                          void *channelContext,
                          const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccNistP256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccNistP256_getBlockSize(const UA_SecurityPolicy *policy,
                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccNistP256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccNistP256_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                   void *channelContext,
                                   const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccNistP256_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccNistP256_setRemoteSymIv(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccNistP256_sign(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)policy->policyContext;
    return UA_mbedTLS_ECDSA_SHA256_Sign(message, &pc->localPrivateKey,
                                        &pc->drbgContext, signature);
}

static UA_StatusCode
UA_AsymSig_EccNistP256_verify(const UA_SecurityPolicy *policy, void *channelContext,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_mbedTLS_ECDSA_SHA256_Verify(message, &cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccNistP256_Dummy(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD; /* Do nothing and return true */
}

static size_t
UA_SymSig_EccNistP256_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccNistP256_verify(const UA_SecurityPolicy *policy, void *channelContext,
                             const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_mbedTLS_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccNistP256_sign(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_mbedTLS_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccNistP256_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccNistP256_decrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;

    if(cc->remoteSymIv.length != UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(data->length % UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
UA_SymEn_EccNistP256_encrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_ECCNISTP256_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
EccNistP256_compareCertificate(const UA_SecurityPolicy *policy,
                               const void *channelContext,
                               const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccNistP256 *cc =
        (const Channel_Context_EccNistP256 *)channelContext;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_x509_crt_free(&cert);
        return retval;
    }

    if(cert.raw.len != cc->remoteCertificateX509.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificateX509.raw.p, cert.raw.len) != 0) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static size_t
UA_AsymEn_EccNistP256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    /* No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccNistP256(UA_SecurityPolicy *sp,
                              const UA_ApplicationType applicationType,
                              const UA_ByteString localCertificate,
                              const UA_ByteString localPrivateKey,
                              const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_nistP256 is deprecated (OPC UA Part 7); "
                   "use ECC_nistP256_AesGcm or ECC_nistP256_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCNISTP256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccNistP256_verify;
    asymSig->sign = UA_AsymSig_EccNistP256_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccNistP256_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccNistP256_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccNistP256_Dummy;
    asymEnc->decrypt = UA_Asym_EccNistP256_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccNistP256_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccNistP256_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccNistP256_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccNistP256_getRemotePlainTextBlockSize;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSig->verify = UA_SymSig_EccNistP256_verify;
    symSig->sign = UA_SymSig_EccNistP256_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccNistP256_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccNistP256_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccNistP256_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccNistP256_getRemoteKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEnc->encrypt = UA_SymEn_EccNistP256_encrypt;
    symEnc->decrypt = UA_SymEn_EccNistP256_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccNistP256_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccNistP256_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccNistP256_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccNistP256_getBlockSize;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = EccNistP256_New_Context;
    sp->deleteChannelContext = EccNistP256_Delete_Context;
    sp->setLocalSymEncryptingKey = EccNistP256_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccNistP256_setLocalSymSigningKey;
    sp->setLocalSymIv = EccNistP256_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccNistP256_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccNistP256_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccNistP256_setRemoteSymIv;
    sp->compareCertificate = EccNistP256_compareCertificate;
    sp->generateKey = UA_Sym_EccNistP256_generateKey;
    sp->generateNonce = UA_Sym_EccNistP256_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCNISTP256_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccNistP256;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccNistP256;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccNistP256;
    sp->createSigningRequest = createSigningRequest_sp_eccnistp256;
    sp->clear = UA_Policy_EccNistP256_Clear_Context;

    /* Parse the certificate */
    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_EccNistP256_New_Context(sp, localPrivateKey, applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 */
#endif /* UA_ENABLE_ENCRYPTION_MBEDTLS */

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_eccnistp384.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x03000000


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha512.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

#define UA_SHA384_LENGTH 48 /* 384 bit */
#define UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNATURE_LENGTH 96
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP384_NONCE_LENGTH_BYTES 96

typedef struct {
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccNistP384;

typedef struct Channel_Context_EccNistP384 {
    mbedtls_pk_context localEphemeralKeyPair;
    UA_Boolean ephemeralKeyInitialized;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    mbedtls_x509_crt remoteCertificateX509;
} Channel_Context_EccNistP384;

static UA_StatusCode
UA_Policy_EccNistP384_New_Context(UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString localPrivateKey,
                                  const UA_ApplicationType applicationType,
                                  const UA_Logger *logger) {
    Policy_Context_EccNistP384 *context = (Policy_Context_EccNistP384 *)
        UA_malloc(sizeof(Policy_Context_EccNistP384));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    mbedtls_pk_init(&context->localPrivateKey);
    mbedtls_pk_init(&context->csrLocalPrivateKey);
    mbedtls_entropy_init(&context->entropyContext);
    mbedtls_ctr_drbg_init(&context->drbgContext);

    int mbedErr = mbedtls_ctr_drbg_seed(&context->drbgContext,
                                         mbedtls_entropy_func,
                                         &context->entropyContext, NULL, 0);
    if(mbedErr) {
        UA_free(context);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &context->localPrivateKey,
                                        &context->entropyContext);
    if(mbedErr) {
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Verify the key is an EC key */
    if(!mbedtls_pk_can_do(&context->localPrivateKey, MBEDTLS_PK_ECKEY)) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval =
        UA_ByteString_allocBuffer(&context->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &context->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&context->localCertThumbprint);
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;
    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccNistP384_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)policy->policyContext;
    if(!pc)
        return;

    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccnistp384(UA_SecurityPolicy *securityPolicy,
                                    const UA_String *subjectName,
                                    const UA_ByteString *nonce,
                                    const UA_KeyValueMap *params,
                                    UA_ByteString *csr,
                                    UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384*)securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey,
                                        &pc->csrLocalPrivateKey,
                                        &pc->entropyContext,
                                        &pc->drbgContext,
                                        securityPolicy, subjectName,
                                        nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccNistP384(UA_SecurityPolicy *securityPolicy,
                                              const UA_ByteString newCertificate,
                                              const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
    int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey,
                                            &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccNistP384_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccNistP384_New_Context(const UA_SecurityPolicy *securityPolicy,
                        const UA_ByteString *remoteCertificate,
                        void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP384 *newContext = (Channel_Context_EccNistP384 *)
        UA_calloc(1, sizeof(Channel_Context_EccNistP384));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_ByteString_copy(remoteCertificate, &newContext->remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    mbedtls_x509_crt_init(&newContext->remoteCertificateX509);
    retval = UA_mbedTLS_LoadCertificate(&newContext->remoteCertificate,
                                        &newContext->remoteCertificateX509);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&newContext->remoteCertificate);
        UA_free(newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    mbedtls_pk_init(&newContext->localEphemeralKeyPair);
    newContext->ephemeralKeyInitialized = UA_FALSE;

    *channelContext = newContext;
    return UA_STATUSCODE_GOOD;
}

static void
EccNistP384_Delete_Context(const UA_SecurityPolicy *policy,
                           void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccNistP384 *cc =
        (Channel_Context_EccNistP384 *)channelContext;
    mbedtls_x509_crt_free(&cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    if(cc->ephemeralKeyInitialized)
        mbedtls_pk_free(&cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccNistP384(const UA_SecurityPolicy *policy,
                                            const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccNistP384(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *certificate,
                                         UA_ByteString *thumbprint) {
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static size_t
UA_Asym_EccNistP384_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccNistP384_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccNistP384_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP384_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP384_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return 1;
}

static UA_StatusCode
UA_Sym_EccNistP384_generateNonce(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *out) {
    Policy_Context_EccNistP384 *pctx =
        (Policy_Context_EccNistP384*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccNistP384 *cctx = (Channel_Context_EccNistP384*)channelContext;
        if(cctx->ephemeralKeyInitialized)
            mbedtls_pk_free(&cctx->localEphemeralKeyPair);
        UA_StatusCode res = UA_mbedTLS_ECC_NISTP384_GenerateKey(
            &cctx->localEphemeralKeyPair, &pctx->drbgContext, out);
        if(res == UA_STATUSCODE_GOOD)
            cctx->ephemeralKeyInitialized = UA_TRUE;
        return res;
    }

    int rc = mbedtls_ctr_drbg_random(&pctx->drbgContext, out->data, out->length);
    return (rc == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccNistP384_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccNistP384_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccNistP384_generateKey(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *secret,
                               const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccNistP384 *pctx =
        (Policy_Context_EccNistP384 *)policy->policyContext;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_mbedTLS_ECC_DeriveKeys(MBEDTLS_ECP_DP_SECP384R1, MBEDTLS_MD_SHA384,
                                     pctx->applicationType,
                                     &cc->localEphemeralKeyPair,
                                     &pctx->drbgContext,
                                     secret, seed, out);
}

static UA_StatusCode
EccNistP384_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                  void *channelContext,
                                  const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccNistP384_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccNistP384_setLocalSymIv(const UA_SecurityPolicy *policy,
                          void *channelContext,
                          const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccNistP384_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccNistP384_getBlockSize(const UA_SecurityPolicy *policy,
                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccNistP384_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccNistP384_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                   void *channelContext,
                                   const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccNistP384_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccNistP384_setRemoteSymIv(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccNistP384_sign(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)policy->policyContext;
    return UA_mbedTLS_ECDSA_SHA384_Sign(message, &pc->localPrivateKey,
                                        &pc->drbgContext, signature);
}

static UA_StatusCode
UA_AsymSig_EccNistP384_verify(const UA_SecurityPolicy *policy, void *channelContext,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_mbedTLS_ECDSA_SHA384_Verify(message, &cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccNistP384_Dummy(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymSig_EccNistP384_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccNistP384_verify(const UA_SecurityPolicy *policy, void *channelContext,
                             const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_mbedTLS_HMAC_SHA384_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccNistP384_sign(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_mbedTLS_HMAC_SHA384_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccNistP384_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccNistP384_decrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;

    if(cc->remoteSymIv.length != UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(data->length % UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_BLOCK_SIZE != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
UA_SymEn_EccNistP384_encrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_ECCNISTP384_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
EccNistP384_compareCertificate(const UA_SecurityPolicy *policy,
                               const void *channelContext,
                               const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccNistP384 *cc =
        (const Channel_Context_EccNistP384 *)channelContext;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_x509_crt_free(&cert);
        return retval;
    }

    if(cert.raw.len != cc->remoteCertificateX509.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificateX509.raw.p, cert.raw.len) != 0) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static size_t
UA_AsymEn_EccNistP384_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccNistP384(UA_SecurityPolicy *sp,
                              const UA_ApplicationType applicationType,
                              const UA_ByteString localCertificate,
                              const UA_ByteString localPrivateKey,
                              const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_nistP384 is deprecated (OPC UA Part 7); "
                   "use ECC_nistP384_AesGcm or ECC_nistP384_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP384\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCNISTP384APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 15;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccNistP384_verify;
    asymSig->sign = UA_AsymSig_EccNistP384_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccNistP384_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccNistP384_getRemoteSignatureSize;

    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccNistP384_Dummy;
    asymEnc->decrypt = UA_Asym_EccNistP384_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccNistP384_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccNistP384_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccNistP384_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccNistP384_getRemotePlainTextBlockSize;

    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-384\0");
    symSig->verify = UA_SymSig_EccNistP384_verify;
    symSig->sign = UA_SymSig_EccNistP384_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccNistP384_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccNistP384_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccNistP384_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccNistP384_getRemoteKeyLength;

    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = UA_SymEn_EccNistP384_encrypt;
    symEnc->decrypt = UA_SymEn_EccNistP384_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccNistP384_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccNistP384_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccNistP384_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccNistP384_getBlockSize;

    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    sp->newChannelContext = EccNistP384_New_Context;
    sp->deleteChannelContext = EccNistP384_Delete_Context;
    sp->setLocalSymEncryptingKey = EccNistP384_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccNistP384_setLocalSymSigningKey;
    sp->setLocalSymIv = EccNistP384_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccNistP384_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccNistP384_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccNistP384_setRemoteSymIv;
    sp->compareCertificate = EccNistP384_compareCertificate;
    sp->generateKey = UA_Sym_EccNistP384_generateKey;
    sp->generateNonce = UA_Sym_EccNistP384_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCNISTP384_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccNistP384;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccNistP384;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccNistP384;
    sp->createSigningRequest = createSigningRequest_sp_eccnistp384;
    sp->clear = UA_Policy_EccNistP384_Clear_Context;

    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = UA_Policy_EccNistP384_New_Context(sp, localPrivateKey, applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 */
#endif /* UA_ENABLE_ENCRYPTION_MBEDTLS */

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_eccbrainpoolp256r1.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x03000000


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNATURE_LENGTH 64
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_KEY_LENGTH 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_NONCE_LENGTH_BYTES 64

typedef struct {
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccBrainpoolP256r1;

typedef struct Channel_Context_EccBrainpoolP256r1 {
    mbedtls_pk_context localEphemeralKeyPair;
    UA_Boolean ephemeralKeyInitialized;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    mbedtls_x509_crt remoteCertificateX509;
} Channel_Context_EccBrainpoolP256r1;

static UA_StatusCode
UA_Policy_EccBrainpoolP256r1_New_Context(UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString localPrivateKey,
                                  const UA_ApplicationType applicationType,
                                  const UA_Logger *logger) {
    Policy_Context_EccBrainpoolP256r1 *context = (Policy_Context_EccBrainpoolP256r1 *)
        UA_malloc(sizeof(Policy_Context_EccBrainpoolP256r1));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    mbedtls_pk_init(&context->localPrivateKey);
    mbedtls_pk_init(&context->csrLocalPrivateKey);
    mbedtls_entropy_init(&context->entropyContext);
    mbedtls_ctr_drbg_init(&context->drbgContext);

    int mbedErr = mbedtls_ctr_drbg_seed(&context->drbgContext,
                                         mbedtls_entropy_func,
                                         &context->entropyContext, NULL, 0);
    if(mbedErr) {
        UA_free(context);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &context->localPrivateKey,
                                        &context->entropyContext);
    if(mbedErr) {
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Verify the key is an EC key */
    if(!mbedtls_pk_can_do(&context->localPrivateKey, MBEDTLS_PK_ECKEY)) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval =
        UA_ByteString_allocBuffer(&context->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &context->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&context->localCertThumbprint);
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;
    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccBrainpoolP256r1_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    if(!pc)
        return;

    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccbrainpoolp256r1(UA_SecurityPolicy *securityPolicy,
                                    const UA_String *subjectName,
                                    const UA_ByteString *nonce,
                                    const UA_KeyValueMap *params,
                                    UA_ByteString *csr,
                                    UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1*)securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey,
                                        &pc->csrLocalPrivateKey,
                                        &pc->entropyContext,
                                        &pc->drbgContext,
                                        securityPolicy, subjectName,
                                        nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccBrainpoolP256r1(UA_SecurityPolicy *securityPolicy,
                                              const UA_ByteString newCertificate,
                                              const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)securityPolicy->policyContext;

    /* Set the certificate */
    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
    int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey,
                                            &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Update the thumbprint */
    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccBrainpoolP256r1_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccBrainpoolP256r1_New_Context(const UA_SecurityPolicy *securityPolicy,
                        const UA_ByteString *remoteCertificate,
                        void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccBrainpoolP256r1 *newContext = (Channel_Context_EccBrainpoolP256r1 *)
        UA_calloc(1, sizeof(Channel_Context_EccBrainpoolP256r1));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_ByteString_copy(remoteCertificate, &newContext->remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    /* Decode to X509 */
    mbedtls_x509_crt_init(&newContext->remoteCertificateX509);
    retval = UA_mbedTLS_LoadCertificate(&newContext->remoteCertificate,
                                        &newContext->remoteCertificateX509);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&newContext->remoteCertificate);
        UA_free(newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    mbedtls_pk_init(&newContext->localEphemeralKeyPair);
    newContext->ephemeralKeyInitialized = UA_FALSE;

    *channelContext = newContext;
    return UA_STATUSCODE_GOOD;
}

static void
EccBrainpoolP256r1_Delete_Context(const UA_SecurityPolicy *policy,
                           void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    mbedtls_x509_crt_free(&cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    if(cc->ephemeralKeyInitialized)
        mbedtls_pk_free(&cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccBrainpoolP256r1(const UA_SecurityPolicy *policy,
                                            const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccBrainpoolP256r1(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *certificate,
                                         UA_ByteString *thumbprint) {
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static size_t
UA_Asym_EccBrainpoolP256r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccBrainpoolP256r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    /* No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP256r1_generateNonce(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP256r1 *pctx =
        (Policy_Context_EccBrainpoolP256r1*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Detect if we want to create an ephemeral key or just cryptographic random
     * data */
    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccBrainpoolP256r1 *cctx = (Channel_Context_EccBrainpoolP256r1*)channelContext;
        if(cctx->ephemeralKeyInitialized)
            mbedtls_pk_free(&cctx->localEphemeralKeyPair);
        UA_StatusCode res = UA_mbedTLS_ECC_BRAINPOOLP256R1_GenerateKey(
            &cctx->localEphemeralKeyPair, &pctx->drbgContext, out);
        if(res == UA_STATUSCODE_GOOD)
            cctx->ephemeralKeyInitialized = UA_TRUE;
        return res;
    }

    int rc = mbedtls_ctr_drbg_random(&pctx->drbgContext, out->data, out->length);
    return (rc == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccBrainpoolP256r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP256r1_generateKey(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *secret,
                               const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP256r1 *pctx =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_mbedTLS_ECC_DeriveKeys(MBEDTLS_ECP_DP_BP256R1, MBEDTLS_MD_SHA256,
                                     pctx->applicationType,
                                     &cc->localEphemeralKeyPair,
                                     &pctx->drbgContext,
                                     secret, seed, out);
}

static UA_StatusCode
EccBrainpoolP256r1_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                  void *channelContext,
                                  const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setLocalSymIv(const UA_SecurityPolicy *policy,
                          void *channelContext,
                          const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccBrainpoolP256r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccBrainpoolP256r1_getBlockSize(const UA_SecurityPolicy *policy,
                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccBrainpoolP256r1_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                   void *channelContext,
                                   const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setRemoteSymIv(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP256r1_sign(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    return UA_mbedTLS_ECDSA_SHA256_Sign(message, &pc->localPrivateKey,
                                        &pc->drbgContext, signature);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP256r1_verify(const UA_SecurityPolicy *policy, void *channelContext,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_mbedTLS_ECDSA_SHA256_Verify(message, &cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccBrainpoolP256r1_Dummy(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD; /* Do nothing and return true */
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP256r1_verify(const UA_SecurityPolicy *policy, void *channelContext,
                             const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_mbedTLS_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP256r1_sign(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_mbedTLS_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP256r1_decrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;

    if(cc->remoteSymIv.length != UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(data->length % UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_BLOCK_SIZE != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP256r1_encrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc = (Channel_Context_EccBrainpoolP256r1 *)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
EccBrainpoolP256r1_compareCertificate(const UA_SecurityPolicy *policy,
                               const void *channelContext,
                               const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccBrainpoolP256r1 *cc =
        (const Channel_Context_EccBrainpoolP256r1 *)channelContext;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_x509_crt_free(&cert);
        return retval;
    }

    if(cert.raw.len != cc->remoteCertificateX509.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificateX509.raw.p, cert.raw.len) != 0) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    /* No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccBrainpoolP256r1(UA_SecurityPolicy *sp,
                              const UA_ApplicationType applicationType,
                              const UA_ByteString localCertificate,
                              const UA_ByteString localPrivateKey,
                              const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_brainpoolP256r1 is deprecated (OPC UA Part 7); "
                   "use ECC_brainpoolP256r1_AesGcm or ECC_brainpoolP256r1_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_brainpoolP256r1\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCBRAINPOOLP256R1APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccBrainpoolP256r1_verify;
    asymSig->sign = UA_AsymSig_EccBrainpoolP256r1_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccBrainpoolP256r1_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccBrainpoolP256r1_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccBrainpoolP256r1_Dummy;
    asymEnc->decrypt = UA_Asym_EccBrainpoolP256r1_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccBrainpoolP256r1_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccBrainpoolP256r1_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccBrainpoolP256r1_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccBrainpoolP256r1_getRemotePlainTextBlockSize;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSig->verify = UA_SymSig_EccBrainpoolP256r1_verify;
    symSig->sign = UA_SymSig_EccBrainpoolP256r1_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccBrainpoolP256r1_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccBrainpoolP256r1_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccBrainpoolP256r1_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccBrainpoolP256r1_getRemoteKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEnc->encrypt = UA_SymEn_EccBrainpoolP256r1_encrypt;
    symEnc->decrypt = UA_SymEn_EccBrainpoolP256r1_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccBrainpoolP256r1_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccBrainpoolP256r1_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccBrainpoolP256r1_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccBrainpoolP256r1_getBlockSize;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = EccBrainpoolP256r1_New_Context;
    sp->deleteChannelContext = EccBrainpoolP256r1_Delete_Context;
    sp->setLocalSymEncryptingKey = EccBrainpoolP256r1_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccBrainpoolP256r1_setLocalSymSigningKey;
    sp->setLocalSymIv = EccBrainpoolP256r1_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccBrainpoolP256r1_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccBrainpoolP256r1_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccBrainpoolP256r1_setRemoteSymIv;
    sp->compareCertificate = EccBrainpoolP256r1_compareCertificate;
    sp->generateKey = UA_Sym_EccBrainpoolP256r1_generateKey;
    sp->generateNonce = UA_Sym_EccBrainpoolP256r1_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccBrainpoolP256r1;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccBrainpoolP256r1;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccBrainpoolP256r1;
    sp->createSigningRequest = createSigningRequest_sp_eccbrainpoolp256r1;
    sp->clear = UA_Policy_EccBrainpoolP256r1_Clear_Context;

    /* Parse the certificate */
    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_EccBrainpoolP256r1_New_Context(sp, localPrivateKey, applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 */
#endif /* UA_ENABLE_ENCRYPTION_MBEDTLS */

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_eccbrainpoolp384r1.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x03000000


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha512.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

#define UA_SHA384_LENGTH 48 /* 384 bit */
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNATURE_LENGTH 96
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_NONCE_LENGTH_BYTES 96

typedef struct {
    mbedtls_pk_context localPrivateKey;
    mbedtls_pk_context csrLocalPrivateKey;
    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccBrainpoolP384r1;

typedef struct Channel_Context_EccBrainpoolP384r1 {
    mbedtls_pk_context localEphemeralKeyPair;
    UA_Boolean ephemeralKeyInitialized;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    mbedtls_x509_crt remoteCertificateX509;
} Channel_Context_EccBrainpoolP384r1;

static UA_StatusCode
UA_Policy_EccBrainpoolP384r1_New_Context(UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString localPrivateKey,
                                  const UA_ApplicationType applicationType,
                                  const UA_Logger *logger) {
    Policy_Context_EccBrainpoolP384r1 *context = (Policy_Context_EccBrainpoolP384r1 *)
        UA_malloc(sizeof(Policy_Context_EccBrainpoolP384r1));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    mbedtls_pk_init(&context->localPrivateKey);
    mbedtls_pk_init(&context->csrLocalPrivateKey);
    mbedtls_entropy_init(&context->entropyContext);
    mbedtls_ctr_drbg_init(&context->drbgContext);

    int mbedErr = mbedtls_ctr_drbg_seed(&context->drbgContext,
                                         mbedtls_entropy_func,
                                         &context->entropyContext, NULL, 0);
    if(mbedErr) {
        UA_free(context);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &context->localPrivateKey,
                                        &context->entropyContext);
    if(mbedErr) {
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Verify the key is an EC key */
    if(!mbedtls_pk_can_do(&context->localPrivateKey, MBEDTLS_PK_ECKEY)) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval =
        UA_ByteString_allocBuffer(&context->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &context->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&context->localCertThumbprint);
        mbedtls_pk_free(&context->localPrivateKey);
        mbedtls_ctr_drbg_free(&context->drbgContext);
        mbedtls_entropy_free(&context->entropyContext);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;
    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccBrainpoolP384r1_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    if(!pc)
        return;

    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_free(&pc->csrLocalPrivateKey);
    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccbrainpoolp384r1(UA_SecurityPolicy *securityPolicy,
                                    const UA_String *subjectName,
                                    const UA_ByteString *nonce,
                                    const UA_KeyValueMap *params,
                                    UA_ByteString *csr,
                                    UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1*)securityPolicy->policyContext;
    return mbedtls_createSigningRequest(&pc->localPrivateKey,
                                        &pc->csrLocalPrivateKey,
                                        &pc->entropyContext,
                                        &pc->drbgContext,
                                        securityPolicy, subjectName,
                                        nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccBrainpoolP384r1(UA_SecurityPolicy *securityPolicy,
                                              const UA_ByteString newCertificate,
                                              const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
    int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey,
                                            &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = mbedtls_thumbprint_sha1(&securityPolicy->localCertificate,
                                     &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccBrainpoolP384r1_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccBrainpoolP384r1_New_Context(const UA_SecurityPolicy *securityPolicy,
                        const UA_ByteString *remoteCertificate,
                        void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccBrainpoolP384r1 *newContext = (Channel_Context_EccBrainpoolP384r1 *)
        UA_calloc(1, sizeof(Channel_Context_EccBrainpoolP384r1));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_ByteString_copy(remoteCertificate, &newContext->remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    mbedtls_x509_crt_init(&newContext->remoteCertificateX509);
    retval = UA_mbedTLS_LoadCertificate(&newContext->remoteCertificate,
                                        &newContext->remoteCertificateX509);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&newContext->remoteCertificate);
        UA_free(newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    mbedtls_pk_init(&newContext->localEphemeralKeyPair);
    newContext->ephemeralKeyInitialized = UA_FALSE;

    *channelContext = newContext;
    return UA_STATUSCODE_GOOD;
}

static void
EccBrainpoolP384r1_Delete_Context(const UA_SecurityPolicy *policy,
                           void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    mbedtls_x509_crt_free(&cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    if(cc->ephemeralKeyInitialized)
        mbedtls_pk_free(&cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccBrainpoolP384r1(const UA_SecurityPolicy *policy,
                                            const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccBrainpoolP384r1(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *certificate,
                                         UA_ByteString *thumbprint) {
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static size_t
UA_Asym_EccBrainpoolP384r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccBrainpoolP384r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return 1;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP384r1_generateNonce(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP384r1 *pctx =
        (Policy_Context_EccBrainpoolP384r1*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccBrainpoolP384r1 *cctx = (Channel_Context_EccBrainpoolP384r1*)channelContext;
        if(cctx->ephemeralKeyInitialized)
            mbedtls_pk_free(&cctx->localEphemeralKeyPair);
        UA_StatusCode res = UA_mbedTLS_ECC_BRAINPOOLP384R1_GenerateKey(
            &cctx->localEphemeralKeyPair, &pctx->drbgContext, out);
        if(res == UA_STATUSCODE_GOOD)
            cctx->ephemeralKeyInitialized = UA_TRUE;
        return res;
    }

    int rc = mbedtls_ctr_drbg_random(&pctx->drbgContext, out->data, out->length);
    return (rc == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccBrainpoolP384r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP384r1_generateKey(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *secret,
                               const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP384r1 *pctx =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_mbedTLS_ECC_DeriveKeys(MBEDTLS_ECP_DP_BP384R1, MBEDTLS_MD_SHA384,
                                     pctx->applicationType,
                                     &cc->localEphemeralKeyPair,
                                     &pctx->drbgContext,
                                     secret, seed, out);
}

static UA_StatusCode
EccBrainpoolP384r1_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                  void *channelContext,
                                  const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setLocalSymIv(const UA_SecurityPolicy *policy,
                          void *channelContext,
                          const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccBrainpoolP384r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccBrainpoolP384r1_getBlockSize(const UA_SecurityPolicy *policy,
                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccBrainpoolP384r1_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                   void *channelContext,
                                   const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setRemoteSymIv(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP384r1_sign(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    return UA_mbedTLS_ECDSA_SHA384_Sign(message, &pc->localPrivateKey,
                                        &pc->drbgContext, signature);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP384r1_verify(const UA_SecurityPolicy *policy, void *channelContext,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_mbedTLS_ECDSA_SHA384_Verify(message, &cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccBrainpoolP384r1_Dummy(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP384r1_verify(const UA_SecurityPolicy *policy, void *channelContext,
                             const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_mbedTLS_HMAC_SHA384_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP384r1_sign(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_mbedTLS_HMAC_SHA384_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP384r1_decrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;

    if(cc->remoteSymIv.length != UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(data->length % UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_BLOCK_SIZE != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP384r1_encrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc = (Channel_Context_EccBrainpoolP384r1 *)channelContext;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data,
                                         keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
EccBrainpoolP384r1_compareCertificate(const UA_SecurityPolicy *policy,
                               const void *channelContext,
                               const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccBrainpoolP384r1 *cc =
        (const Channel_Context_EccBrainpoolP384r1 *)channelContext;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
    if(retval != UA_STATUSCODE_GOOD) {
        mbedtls_x509_crt_free(&cert);
        return retval;
    }

    if(cert.raw.len != cc->remoteCertificateX509.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificateX509.raw.p, cert.raw.len) != 0) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccBrainpoolP384r1(UA_SecurityPolicy *sp,
                              const UA_ApplicationType applicationType,
                              const UA_ByteString localCertificate,
                              const UA_ByteString localPrivateKey,
                              const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_brainpoolP384r1 is deprecated (OPC UA Part 7); "
                   "use ECC_brainpoolP384r1_AesGcm or ECC_brainpoolP384r1_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_brainpoolP384r1\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCBRAINPOOLP384R1APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 15;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccBrainpoolP384r1_verify;
    asymSig->sign = UA_AsymSig_EccBrainpoolP384r1_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccBrainpoolP384r1_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccBrainpoolP384r1_getRemoteSignatureSize;

    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccBrainpoolP384r1_Dummy;
    asymEnc->decrypt = UA_Asym_EccBrainpoolP384r1_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccBrainpoolP384r1_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccBrainpoolP384r1_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccBrainpoolP384r1_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccBrainpoolP384r1_getRemotePlainTextBlockSize;

    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-384\0");
    symSig->verify = UA_SymSig_EccBrainpoolP384r1_verify;
    symSig->sign = UA_SymSig_EccBrainpoolP384r1_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccBrainpoolP384r1_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccBrainpoolP384r1_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccBrainpoolP384r1_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccBrainpoolP384r1_getRemoteKeyLength;

    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = UA_SymEn_EccBrainpoolP384r1_encrypt;
    symEnc->decrypt = UA_SymEn_EccBrainpoolP384r1_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccBrainpoolP384r1_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccBrainpoolP384r1_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccBrainpoolP384r1_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccBrainpoolP384r1_getBlockSize;

    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    sp->newChannelContext = EccBrainpoolP384r1_New_Context;
    sp->deleteChannelContext = EccBrainpoolP384r1_Delete_Context;
    sp->setLocalSymEncryptingKey = EccBrainpoolP384r1_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccBrainpoolP384r1_setLocalSymSigningKey;
    sp->setLocalSymIv = EccBrainpoolP384r1_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccBrainpoolP384r1_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccBrainpoolP384r1_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccBrainpoolP384r1_setRemoteSymIv;
    sp->compareCertificate = EccBrainpoolP384r1_compareCertificate;
    sp->generateKey = UA_Sym_EccBrainpoolP384r1_generateKey;
    sp->generateNonce = UA_Sym_EccBrainpoolP384r1_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccBrainpoolP384r1;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccBrainpoolP384r1;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccBrainpoolP384r1;
    sp->createSigningRequest = createSigningRequest_sp_eccbrainpoolp384r1;
    sp->clear = UA_Policy_EccBrainpoolP384r1_Clear_Context;

    UA_StatusCode res =
        UA_mbedTLS_LoadLocalCertificate(&localCertificate, &sp->localCertificate);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = UA_Policy_EccBrainpoolP384r1_New_Context(sp, localPrivateKey, applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif /* MBEDTLS_VERSION_NUMBER >= 0x03000000 */
#endif /* UA_ENABLE_ENCRYPTION_MBEDTLS */

/**** amalgamated original file "/plugins/crypto/mbedtls/create_certificate.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright (c) 2023 Fraunhofer IOSB (Author: Noel Graf)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 *
 */


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)


#include <time.h>

#include <mbedtls/x509_crt.h>
#include <mbedtls/oid.h>
#include <mbedtls/asn1write.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/platform.h>
#include <mbedtls/version.h>

#define SET_OID(x, oid) \
    do { x.len = MBEDTLS_OID_SIZE(oid); x.p = (unsigned char *) oid; } while (0)

typedef struct mbedtls_write_san_node{
    int type;
    char* host;
    size_t hostlen;
} mbedtls_write_san_node;

typedef struct mbedtls_write_san_list{
    mbedtls_write_san_node node;
    struct mbedtls_write_san_list* next;
} mbedtls_write_san_list;

static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist);

int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist);

#if MBEDTLS_VERSION_NUMBER < 0x03030000
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
                                            const mbedtls_asn1_sequence *exts);
#endif

static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
                             UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
                             void *p_rng);

static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey);

/* Case-insensitive comparison of a UA_String with a C string literal */
static UA_Boolean
uaStringEqualsCI_mbedtls(const UA_String *uaStr, const char *cStr) {
    size_t cLen = strlen(cStr);
    if(uaStr->length != cLen)
        return false;
    for(size_t i = 0; i < cLen; i++) {
        char a = (char)uaStr->data[i];
        char b = cStr[i];
        if(a >= 'A' && a <= 'Z') a = (char)(a + 32);
        if(b >= 'A' && b <= 'Z') b = (char)(b + 32);
        if(a != b) return false;
    }
    return true;
}

UA_StatusCode
UA_CreateCertificate(const UA_Logger *logger, const UA_String *subject,
                     size_t subjectSize, const UA_String *subjectAltName,
                     size_t subjectAltNameSize, UA_CertificateFormat certFormat,
                     UA_KeyValueMap *params, UA_ByteString *outPrivateKey,
                     UA_ByteString *outCertificate) {
    if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || !subject ||
       subjectAltNameSize == 0 || subjectSize == 0 ||
       (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Use the maximum size */
    UA_UInt16 keySizeBits = 4096;
    /* Default to 1 year */
    UA_UInt16 expiresInDays = 365;
    /* Key type: 0 = RSA (default), 1 = EC */
    int keyTypeEC = 0;
    UA_String eccCurve = UA_STRING_STATIC("prime256v1");

    if(params) {
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
        if(keySizeBitsValue)
            keySizeBits = *keySizeBitsValue;

        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
        if(expiresInDaysValue)
            expiresInDays = *expiresInDaysValue;

        const UA_String *keyTypeValue = (const UA_String *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "key-type"), &UA_TYPES[UA_TYPES_STRING]);
        if(keyTypeValue && uaStringEqualsCI_mbedtls(keyTypeValue, "ec"))
            keyTypeEC = 1;

        const UA_String *eccCurveValue = (const UA_String *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "ecc-curve"), &UA_TYPES[UA_TYPES_STRING]);
        if(eccCurveValue && eccCurveValue->length > 0)
            eccCurve = *eccCurveValue;
    }

    UA_ByteString_init(outPrivateKey);
    UA_ByteString_init(outCertificate);

    mbedtls_pk_context key;
    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_entropy_context entropy;
    const char *pers = "gen_key";
    mbedtls_x509write_cert crt;

    UA_StatusCode errRet = UA_STATUSCODE_GOOD;

    /* Set to sane values */
    mbedtls_pk_init(&key);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    mbedtls_entropy_init(&entropy);
    mbedtls_x509write_crt_init(&crt);

    /* Seed the random number generator */
    if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Failed to initialize the random number generator.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Generate a key pair */
    if(keyTypeEC) {
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
        /* Map curve name to mbedTLS group ID */
        mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_SECP256R1; /* default: P-256 */
        if(uaStringEqualsCI_mbedtls(&eccCurve, "prime256v1") ||
           uaStringEqualsCI_mbedtls(&eccCurve, "nistp256"))
            grp_id = MBEDTLS_ECP_DP_SECP256R1;
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "secp384r1") ||
                uaStringEqualsCI_mbedtls(&eccCurve, "nistp384"))
            grp_id = MBEDTLS_ECP_DP_SECP384R1;
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "brainpoolp256r1"))
            grp_id = MBEDTLS_ECP_DP_BP256R1;
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "brainpoolp384r1"))
            grp_id = MBEDTLS_ECP_DP_BP384R1;
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "ed25519") ||
                uaStringEqualsCI_mbedtls(&eccCurve, "ed448")) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "EdDSA (Curve25519/Curve448) certificate generation "
                         "is not supported with mbedTLS. Use OpenSSL.");
            errRet = UA_STATUSCODE_BADNOTIMPLEMENTED;
            goto cleanup;
        } else {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Create Certificate: Unsupported ECC curve for mbedTLS.");
            errRet = UA_STATUSCODE_BADINVALIDARGUMENT;
            goto cleanup;
        }

        if(mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) != 0 ||
           mbedtls_ecp_gen_key(grp_id, mbedtls_pk_ec(key),
                               mbedtls_ctr_drbg_random, &ctr_drbg) != 0) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Failed to generate ECC key pair.");
            errRet = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
#else
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "ECC certificate generation requires mbedTLS >= 3.0.");
        errRet = UA_STATUSCODE_BADNOTIMPLEMENTED;
        goto cleanup;
#endif
    } else {
        /* Generate an RSA key pair */
        if(mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 ||
           mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random,
                               &ctr_drbg, keySizeBits, 65537) != 0) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Failed to generate RSA key pair.");
            errRet = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
    }

    /* Setting certificate values */
    mbedtls_x509write_crt_set_version(&crt, MBEDTLS_X509_CRT_VERSION_3);
    /* P-384 / brainpoolP384r1 use SHA-384; everything else uses SHA-256 */
    if(keyTypeEC &&
       (uaStringEqualsCI_mbedtls(&eccCurve, "secp384r1") ||
        uaStringEqualsCI_mbedtls(&eccCurve, "nistp384") ||
        uaStringEqualsCI_mbedtls(&eccCurve, "brainpoolp384r1")))
        mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA384);
    else
        mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);

    size_t subject_char_len = 0;
    for(size_t i = 0; i < subjectSize; i++) {
        subject_char_len += subject[i].length;
    }
    char *subject_char = (char*)UA_malloc(subject_char_len + subjectSize);
    if(!subject_char) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Cannot allocate memory for subject. Out of memory.");
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    size_t pos = 0;
    for(size_t i = 0; i < subjectSize; i++) {
        subject_char_len += subject[i].length;
        memcpy(subject_char + pos, subject[i].data, subject[i].length);
        pos += subject[i].length;
        if(i < subjectSize - 1)
            subject_char[pos++] = ',';
        else
            subject_char[pos++] = '\0';
    }

    if((mbedtls_x509write_crt_set_subject_name(&crt, subject_char)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting subject failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        UA_free(subject_char);
        goto cleanup;
    }

    if((mbedtls_x509write_crt_set_issuer_name(&crt, subject_char)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting issuer failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        UA_free(subject_char);
        goto cleanup;
    }

    UA_free(subject_char);

    mbedtls_write_san_list *cur = NULL;
    mbedtls_write_san_list *cur_tmp = NULL;
    mbedtls_write_san_list *head = NULL;
    for(size_t i = 0; i < subjectAltNameSize; i++) {
        /* Copy and null-terminate */
        char *subAlt = (char *)UA_malloc(subjectAltName[i].length + 1);
        memcpy(subAlt, subjectAltName[i].data, subjectAltName[i].length);
        subAlt[subjectAltName[i].length] = 0;

        /* split into SAN type and value */
        char *sanType = NULL;
        for(char *char_pos = subAlt; *char_pos != 0; char_pos++) {
            if(*char_pos == ':') {
                *char_pos = '\0';
                sanType = subAlt;
                break;
            }
        }

        if(!sanType) {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Invalid Input format");
            UA_free(subAlt);
            continue;
        }

        char *sanValue = (char *)subjectAltName[i].data + strlen(sanType) + 1;
        size_t sanValueLength = subjectAltName[i].length - strlen(sanType) - 1;

        cur_tmp = (mbedtls_write_san_list*)mbedtls_calloc(1, sizeof(mbedtls_write_san_list));
        cur_tmp->next = NULL;
        cur_tmp->node.host = sanValue;
        cur_tmp->node.hostlen = sanValueLength;

        if(strcmp(sanType, "DNS") == 0) {
            cur_tmp->node.type = MBEDTLS_X509_SAN_DNS_NAME;
        } else if(strcmp(sanType, "URI") == 0) {
            cur_tmp->node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
        } else if(strcmp(sanType, "IP") == 0) {
            uint8_t ip[4] = {0};
            if(musl_inet_pton(AF_INET, sanValue, ip) <= 0) {
                UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "IP SAN preparation failed");
                mbedtls_free(cur_tmp);
                UA_free(subAlt);
                continue;
            }
            cur_tmp->node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
            cur_tmp->node.host = (char *)ip;
            cur_tmp->node.hostlen = sizeof(ip);
        } else if(strcmp(sanType, "RFC822") == 0) {
            cur_tmp->node.type = MBEDTLS_X509_SAN_RFC822_NAME;
        } else {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Given an unsupported SAN");
            mbedtls_free(cur_tmp);
            UA_free(subAlt);
            continue;
        }

        if(!cur) {
            cur = cur_tmp;
            head = cur_tmp;
        } else {
            cur->next = cur_tmp;
            cur = cur->next;
        }

        UA_free(subAlt);
    }

    if((mbedtls_x509write_crt_set_subject_alt_name(&crt, head)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting subject alternative name failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        while(head != NULL) {
            cur_tmp = head->next;
            mbedtls_free(head);
            head = cur_tmp;
        }
        goto cleanup;
    }

    while(head != NULL) {
        cur_tmp = head->next;
        mbedtls_free(head);
        head = cur_tmp;
    }

#if MBEDTLS_VERSION_NUMBER >= 0x03040000
    unsigned char *serial = (unsigned char *)"1";
    size_t serial_len = 1;
    mbedtls_x509write_crt_set_serial_raw(&crt, serial, serial_len);
#else
    mbedtls_mpi serial_mpi;
    mbedtls_mpi_init(&serial_mpi);
    mbedtls_mpi_lset(&serial_mpi, 1);
    mbedtls_x509write_crt_set_serial(&crt, &serial_mpi);
    mbedtls_mpi_free(&serial_mpi);
#endif

    /* Get the current time */
    time_t rawTime;
    struct tm *timeInfo;
    time(&rawTime);
    timeInfo = gmtime(&rawTime);

    /* Format the current timestamp */
    char current_timestamp[15];  // YYYYMMDDhhmmss + '\0'
    strftime(current_timestamp, sizeof(current_timestamp), "%Y%m%d%H%M%S", timeInfo);

    /* Calculate the future timestamp */
    timeInfo->tm_mday += expiresInDays;
    time_t future_time = mktime(timeInfo);

    /* Format the future timestamp */
    char future_timestamp[15];  // YYYYMMDDhhmmss + '\0'
    strftime(future_timestamp, sizeof(future_timestamp), "%Y%m%d%H%M%S", gmtime(&future_time));

    if(mbedtls_x509write_crt_set_validity(&crt, current_timestamp, future_timestamp) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting 'not before' and 'not after' failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(mbedtls_x509write_crt_set_basic_constraints(&crt, 0, -1) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting basic constraints failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* ECC certificates need keyAgreement for ECDH instead of keyEncipherment */
    unsigned int keyUsageFlags = keyTypeEC
        ? (MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION
           | MBEDTLS_X509_KU_KEY_AGREEMENT | MBEDTLS_X509_KU_KEY_CERT_SIGN)
        : (MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION
           | MBEDTLS_X509_KU_KEY_ENCIPHERMENT | MBEDTLS_X509_KU_DATA_ENCIPHERMENT
           | MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN);
    if(mbedtls_x509write_crt_set_key_usage(&crt, keyUsageFlags) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting key usage failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    mbedtls_asn1_sequence *ext_key_usage;
    ext_key_usage = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
    ext_key_usage->buf.tag = MBEDTLS_ASN1_OID;
    SET_OID(ext_key_usage->buf, MBEDTLS_OID_SERVER_AUTH);
    ext_key_usage->next = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
    ext_key_usage->next->buf.tag = MBEDTLS_ASN1_OID;
    SET_OID(ext_key_usage->next->buf, MBEDTLS_OID_CLIENT_AUTH);

    if(mbedtls_x509write_crt_set_ext_key_usage(&crt, ext_key_usage) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting extended key usage failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        mbedtls_free(ext_key_usage->next);
        mbedtls_free(ext_key_usage);
        goto cleanup;
    }

    mbedtls_free(ext_key_usage->next);
    mbedtls_free(ext_key_usage);

    mbedtls_x509write_crt_set_subject_key(&crt, &key);
    mbedtls_x509write_crt_set_issuer_key(&crt, &key);


    /* Write private key */
    if ((write_private_key(&key, certFormat, outPrivateKey)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Writing private key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Write Certificate */
    if ((write_certificate(&crt, certFormat, outCertificate,
                                 mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Writing certificate failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    mbedtls_x509write_crt_free(&crt);
    mbedtls_pk_free(&key);

cleanup:
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    mbedtls_x509write_crt_free(&crt);
    mbedtls_pk_free(&key);
    return errRet;
}

static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey) {
    int ret;
    unsigned char output_buf[16000];
    unsigned char *c = output_buf;
    size_t len = 0;

    memset(output_buf, 0, sizeof(output_buf));
    switch(keyFormat) {
    case UA_CERTIFICATEFORMAT_DER: {
        if((ret = mbedtls_pk_write_key_der(key, output_buf, sizeof(output_buf))) < 0) {
            return ret;
        }

        len = (size_t)ret;
        c = output_buf + sizeof(output_buf) - len;
        break;
    }
    case UA_CERTIFICATEFORMAT_PEM: {
        if((ret = mbedtls_pk_write_key_pem(key, output_buf, sizeof(output_buf))) != 0) {
            return ret;
        }

        len = strlen((char *)output_buf);
        break;
    }
    }

    outPrivateKey->length = len;
    UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
    memcpy(outPrivateKey->data, c, outPrivateKey->length);

    return 0;
}

static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
                      UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
                      void *p_rng) {
    int ret;
    unsigned char output_buf[4096];
    unsigned char *c = output_buf;
    size_t len = 0;

    memset(output_buf, 0, sizeof(output_buf));
    switch(certFormat) {
    case UA_CERTIFICATEFORMAT_DER: {
        if((ret = mbedtls_x509write_crt_der(crt, output_buf, sizeof(output_buf), f_rng, p_rng)) < 0) {
            return ret;
        }

        len = (size_t)ret;
        c = output_buf + sizeof(output_buf) - len;
        break;
    }
    case UA_CERTIFICATEFORMAT_PEM: {
        if((ret = mbedtls_x509write_crt_pem(crt, output_buf, sizeof(output_buf), f_rng, p_rng)) < 0) {
            return ret;
        }

        len = strlen((char *)output_buf);
        break;
    }
    }

    outCertificate->length = len;
    UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
    memcpy(outCertificate->data, c, outCertificate->length);

    return 0;
}

#if MBEDTLS_VERSION_NUMBER < 0x03030000
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
                                            const mbedtls_asn1_sequence *exts) {
    unsigned char buf[256];
    unsigned char *c = buf + sizeof(buf);
    int ret;
    size_t len = 0;
    const mbedtls_asn1_sequence *last_ext = NULL;
    const mbedtls_asn1_sequence *ext;

    memset(buf, 0, sizeof(buf));

    /* We need at least one extension: SEQUENCE SIZE (1..MAX) OF KeyPurposeId */
    if(!exts) {
        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
    }

    /* Iterate over exts backwards, so we write them out in the requested order */
    while(last_ext != exts) {
        for(ext = exts; ext->next != last_ext; ext = ext->next) {
        }
        if(ext->buf.tag != MBEDTLS_ASN1_OID) {
            return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
        }
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, buf, ext->buf.p, ext->buf.len));
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, ext->buf.len));
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_OID));
        last_ext = ext;
    }

    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));

    return mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_EXTENDED_KEY_USAGE,
                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE), 1, c, len);
}

#endif

static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist) {
    size_t ret = 0;
    const mbedtls_write_san_list* cur = sanlist;
    while (cur) {
        ++ret;
        cur = cur->next;
    }

    return ret;
}

int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist) {
    int ret = 0;
    size_t sandeep = 0;
    const mbedtls_write_san_list* cur = sanlist;
    unsigned char* buf;
    unsigned char* pc;
    size_t len;
    size_t buflen = 0;

    /* How many alt names to be written */
    sandeep = mbedtls_get_san_list_deep(sanlist);
    if (sandeep == 0)
        return ret;

    buflen = MBEDTLS_SAN_MAX_LEN * sandeep + sandeep;
    buf = (unsigned char *)mbedtls_calloc(1, buflen);
    if(!buf)
        return MBEDTLS_ERR_ASN1_ALLOC_FAILED;

    memset(buf, 0, buflen);
    pc = buf + buflen;

    len = 0;
    while(cur) {
        switch (cur->node.type) {
        case MBEDTLS_X509_SAN_DNS_NAME:
        case MBEDTLS_X509_SAN_RFC822_NAME:
        case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
        case MBEDTLS_X509_SAN_IP_ADDRESS:
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
                                         mbedtls_asn1_write_raw_buffer(&pc, buf, (const unsigned char *)cur->node.host,
                                                                       cur->node.hostlen));
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, cur->node.hostlen));
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf,
                                                                     MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
            break;
        default:
            /* Error out on an unsupported SAN */
            ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
            goto cleanup;
        }

        cur = cur->next;
    }

    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, len));
    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));

    ret = mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_SUBJECT_ALT_NAME,
                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME), 0, buf + buflen - len, len);

    mbedtls_free(buf);
    return ret;

cleanup:
    mbedtls_free(buf);
    return ret;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/certificategroup.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS

#include <mbedtls/x509.h>
#include <mbedtls/oid.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/entropy.h>
#include <mbedtls/version.h>
#include <mbedtls/sha256.h>
#if defined(MBEDTLS_USE_PSA_CRYPTO)
#include <mbedtls/psa_util.h>
#endif


/* Configuration parameters */

#define MEMORYCERTSTORE_PARAMETERSSIZE 2
#define MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE 0
#define MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE 1

static const struct {
    UA_QualifiedName name;
    const UA_DataType *type;
    UA_Boolean required;
} MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMETERSSIZE] = {
    {{0, UA_STRING_STATIC("max-trust-listsize")}, &UA_TYPES[UA_TYPES_UINT16], false},
    {{0, UA_STRING_STATIC("max-rejected-listsize")}, &UA_TYPES[UA_TYPES_STRING], false}
};

typedef struct {
    UA_TrustListDataType trustList;
    size_t rejectedCertificatesSize;
    UA_ByteString *rejectedCertificates;

    UA_UInt32 maxTrustListSize;
    UA_UInt32 maxRejectedListSize;

    UA_Boolean reloadRequired;

    mbedtls_x509_crt trustedCertificates;
    mbedtls_x509_crt issuerCertificates;
    mbedtls_x509_crl trustedCrls;
    mbedtls_x509_crl issuerCrls;
} MemoryCertStore;

static UA_Boolean mbedtlsCheckCA(mbedtls_x509_crt *cert);

static UA_StatusCode
MemoryCertStore_removeFromTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    context->reloadRequired = true;
    return UA_TrustListDataType_remove(trustList, &context->trustList);
}

static UA_StatusCode
MemoryCertStore_getTrustList(UA_CertificateGroup *certGroup, UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    return UA_TrustListDataType_copy(&context->trustList, trustList);
}

static UA_StatusCode
MemoryCertStore_setTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    context->reloadRequired = true;
    /* Remove the section of the trust list that needs to be reset, while keeping the remaining parts intact */
    return UA_TrustListDataType_set(trustList, &context->trustList);
}

static UA_StatusCode
MemoryCertStore_addToTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(&context->trustList) + UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    context->reloadRequired = true;
    return UA_TrustListDataType_add(trustList, &context->trustList);
}

static UA_StatusCode
MemoryCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **rejectedList, size_t *rejectedListSize) {
    /* Check parameter */
    if(certGroup == NULL || rejectedList == NULL || rejectedListSize == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    UA_StatusCode retval = UA_Array_copy(context->rejectedCertificates, context->rejectedCertificatesSize,
                                         (void**)rejectedList, &UA_TYPES[UA_TYPES_BYTESTRING]);

    if(retval == UA_STATUSCODE_GOOD)
        *rejectedListSize = context->rejectedCertificatesSize;

    return retval;
}

static UA_StatusCode
mbedtlsCheckCrlMatch(mbedtls_x509_crt *cert, mbedtls_x509_crl *crl) {
    char certSubject[MBEDTLS_X509_MAX_DN_NAME_SIZE];
    char crlIssuer[MBEDTLS_X509_MAX_DN_NAME_SIZE];

    mbedtls_x509_dn_gets(certSubject, sizeof(certSubject), &cert->subject);
    mbedtls_x509_dn_gets(crlIssuer, sizeof(crlIssuer), &crl->issuer);

    if(strncmp(certSubject, crlIssuer, MBEDTLS_X509_MAX_DN_NAME_SIZE) == 0)
        return UA_STATUSCODE_GOOD;

    return UA_STATUSCODE_BADNOMATCH;
}

static UA_StatusCode
mbedtlsFindCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
             const UA_ByteString *crlList, const size_t crlListSize,
             UA_ByteString **crls, size_t *crlsSize) {
    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
            "An error occurred while parsing the certificate.");
        return retval;
    }

    /* Check if the certificate is a CA certificate.
     * Only a CA certificate can have a CRL. */
    if(!mbedtlsCheckCA(&cert)) {
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
               "The certificate is not a CA certificate and therefore does not have a CRL.");
        mbedtls_x509_crt_free(&cert);
        return UA_STATUSCODE_GOOD;
    }

    UA_Boolean foundMatch = false;
    for(size_t i = 0; i < crlListSize; i++) {
        mbedtls_x509_crl crl;
        mbedtls_x509_crl_init(&crl);
        retval = UA_mbedTLS_LoadCrl(&crlList[i], &crl);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                "An error occurred while parsing the crl.");
            mbedtls_x509_crt_free(&cert);
            return retval;
        }

        retval = mbedtlsCheckCrlMatch(&cert, &crl);
        mbedtls_x509_crl_free(&crl);
        if(retval != UA_STATUSCODE_GOOD) {
            continue;
        }

        /* Continue the search, as a certificate may be associated with multiple CRLs. */
        foundMatch = true;
        retval = UA_Array_appendCopy((void **)crls, crlsSize, &crlList[i],
                                 &UA_TYPES[UA_TYPES_BYTESTRING]);
        if(retval != UA_STATUSCODE_GOOD) {
            mbedtls_x509_crt_free(&cert);
            return retval;
        }
    }
    mbedtls_x509_crt_free(&cert);

    if(!foundMatch)
        return UA_STATUSCODE_BADNOMATCH;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
MemoryCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
                                   const UA_Boolean isTrusted, UA_ByteString **crls,
                                   size_t *crlsSize) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL || crls == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;

    if(isTrusted) {
        return mbedtlsFindCrls(certGroup, certificate,
                               context->trustList.trustedCrls,
                               context->trustList.trustedCrlsSize, crls,
                               crlsSize);
    }
    return mbedtlsFindCrls(certGroup, certificate,
                           context->trustList.issuerCrls,
                           context->trustList.issuerCrlsSize, crls,
                           crlsSize);
}

static UA_StatusCode
MemoryCertStore_addToRejectedList(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;

    /* check duplicate certificate */
    for(size_t i = 0; i < context->rejectedCertificatesSize; i++) {
        if(UA_ByteString_equal(certificate, &context->rejectedCertificates[i]))
            return UA_STATUSCODE_GOOD; /* certificate already exist */
    }

    /* Store rejected certificate */
    if(context->maxRejectedListSize == 0 || context->rejectedCertificatesSize < context->maxRejectedListSize) {
        return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
                                   certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
    }
    UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
    context->rejectedCertificates = NULL;
    context->rejectedCertificatesSize = 0;
    return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
                               certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
}

static void
MemoryCertStore_clear(UA_CertificateGroup *certGroup) {
    /* check parameter */
    if(certGroup == NULL) {
        return;
    }

    UA_NodeId_clear(&certGroup->certificateGroupId);

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context) {
        UA_TrustListDataType_clear(&context->trustList);

        UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        context->rejectedCertificates = NULL;
        context->rejectedCertificatesSize = 0;

        mbedtls_x509_crt_free(&context->trustedCertificates);
        mbedtls_x509_crt_free(&context->issuerCertificates);
        mbedtls_x509_crl_free(&context->trustedCrls);
        mbedtls_x509_crl_free(&context->issuerCrls);

        UA_free(context);
        certGroup->context = NULL;
    }
}

static UA_StatusCode
reloadCertificates(UA_CertificateGroup *certGroup) {
    /* Check parameter */
    if(certGroup == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    UA_ByteString data;
    UA_ByteString_init(&data);
    int err = 0;

    mbedtls_x509_crt_free(&context->trustedCertificates);
    mbedtls_x509_crt_init(&context->trustedCertificates);
    for(size_t i = 0; i < context->trustList.trustedCertificatesSize; ++i) {
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.trustedCertificates[i]);
        err = mbedtls_x509_crt_parse(&context->trustedCertificates, data.data, data.length);
        UA_ByteString_clear(&data);
        if(err)
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    mbedtls_x509_crt_free(&context->issuerCertificates);
    mbedtls_x509_crt_init(&context->issuerCertificates);
    for(size_t i = 0; i < context->trustList.issuerCertificatesSize; ++i) {
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.issuerCertificates[i]);
        err = mbedtls_x509_crt_parse(&context->issuerCertificates, data.data, data.length);
        UA_ByteString_clear(&data);
        if(err)
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    mbedtls_x509_crl_free(&context->trustedCrls);
    mbedtls_x509_crl_init(&context->trustedCrls);
    for(size_t i = 0; i < context->trustList.trustedCrlsSize; i++) {
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.trustedCrls[i]);
        err = mbedtls_x509_crl_parse(&context->trustedCrls, data.data, data.length);
        UA_ByteString_clear(&data);
        if(err)
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    mbedtls_x509_crl_free(&context->issuerCrls);
    mbedtls_x509_crl_init(&context->issuerCrls);
    for(size_t i = 0; i < context->trustList.issuerCrlsSize; i++) {
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.issuerCrls[i]);
        err = mbedtls_x509_crl_parse(&context->issuerCrls, data.data, data.length);
        UA_ByteString_clear(&data);
        if(err)
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    return UA_STATUSCODE_GOOD;
}

#define UA_MBEDTLS_MAX_CHAIN_LENGTH 10
#define UA_MBEDTLS_MAX_DN_LENGTH 256

/* We need to access some private fields below */
#ifndef MBEDTLS_PRIVATE
#define MBEDTLS_PRIVATE(x) x
#endif

/* Is the certificate a CA? */
static UA_Boolean
mbedtlsCheckCA(mbedtls_x509_crt *cert) {
    /* The Basic Constraints extension must be set and the cert acts as CA */
    if(!(cert->MBEDTLS_PRIVATE(ext_types) & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) ||
       !cert->MBEDTLS_PRIVATE(ca_istrue))
        return false;

    /* The Key Usage extension must be set to cert signing and CRL issuing */
    if(!(cert->MBEDTLS_PRIVATE(ext_types) & MBEDTLS_X509_EXT_KEY_USAGE) ||
       mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0 ||
       mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_CRL_SIGN) != 0)
        return false;

    return true;
}

static UA_Boolean
mbedtlsSameName(UA_String name, const mbedtls_x509_name *name2) {
    char buf[UA_MBEDTLS_MAX_DN_LENGTH];
    int len = mbedtls_x509_dn_gets(buf, UA_MBEDTLS_MAX_DN_LENGTH, name2);
    if(len < 0)
        return false;
    UA_String nameString = {(size_t)len, (UA_Byte*)buf};
    return UA_String_equal(&name, &nameString);
}

static UA_Boolean
mbedtlsSameBuf(mbedtls_x509_buf *a, mbedtls_x509_buf *b) {
    if(a->len != b->len)
        return false;
    return (memcmp(a->p, b->p, a->len) == 0);
}

/* Return the first matching issuer candidate AFTER prev.
 * This can return the cert itself if self-signed. */
static mbedtls_x509_crt *
mbedtlsFindNextIssuer(MemoryCertStore *ctx, mbedtls_x509_crt *stack,
                      mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) {
    char inbuf[UA_MBEDTLS_MAX_DN_LENGTH];
    int nameLen = mbedtls_x509_dn_gets(inbuf, UA_MBEDTLS_MAX_DN_LENGTH, &cert->issuer);
    if(nameLen < 0)
        return NULL;
    UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf};
    do {
        for(mbedtls_x509_crt *i = stack; i; i = i->next) {
            if(prev) {
                if(prev == i)
                    prev = NULL; /* This was the last issuer we tried to verify */
                continue;
            }
            /* Compare issuer name and subject name.
             * Skip when the key does not match the signature. */
            if(mbedtlsSameName(issuerName, &i->subject) &&
               mbedtls_pk_can_do(&i->pk, cert->MBEDTLS_PRIVATE(sig_pk)))
                return i;
        }

        /* Switch from the stack that came with the cert to the issuer list and
         * then to the trust list. */
        if(stack == &ctx->trustedCertificates)
            stack = NULL;
        else if(stack == &ctx->issuerCertificates)
            stack = &ctx->trustedCertificates;
        else
            stack = &ctx->issuerCertificates;
    } while(stack);
    return NULL;
}

static UA_StatusCode
mbedtlsCheckRevoked(UA_CertificateGroup *cg, MemoryCertStore *ctx, mbedtls_x509_crt *cert) {
    /* Parse the Issuer Name */
    char inbuf[UA_MBEDTLS_MAX_DN_LENGTH];
    int nameLen = mbedtls_x509_dn_gets(inbuf, UA_MBEDTLS_MAX_DN_LENGTH, &cert->issuer);
    if(nameLen < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf};

    if(ctx->trustedCrls.raw.len == 0 && ctx->issuerCrls.raw.len == 0) {
        UA_LOG_WARNING(cg->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                       "Zero revocation lists have been loaded. "
                       "This seems intentional - omitting the check.");
        return UA_STATUSCODE_GOOD;
    }

    /* Loop over the crl and match the Issuer Name */
    UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
    for(mbedtls_x509_crl *crl = &ctx->trustedCrls; crl; crl = crl->next) {
        /* Is the CRL for certificates from the cert issuer?
         * Is the serial number of the certificate contained in the CRL? */
        if(mbedtlsSameName(issuerName, &crl->issuer)) {
            if(mbedtls_x509_crt_is_revoked(cert, crl) != 0)
                return UA_STATUSCODE_BADCERTIFICATEREVOKED;
            res = UA_STATUSCODE_GOOD; /* There was at least one crl that did not revoke (so far) */
        }
    }

    /* Loop over the issuer crls separately */
    for(mbedtls_x509_crl *crl = &ctx->issuerCrls; crl; crl = crl->next) {
        if(mbedtlsSameName(issuerName, &crl->issuer)) {
            if(mbedtls_x509_crt_is_revoked(cert, crl) != 0)
                return UA_STATUSCODE_BADCERTIFICATEREVOKED;
            res = UA_STATUSCODE_GOOD;
        }
    }

    return res;
}

/* Verify that the public key of the issuer was used to sign the certificate */
static UA_Boolean
mbedtlsCheckSignature(const mbedtls_x509_crt *cert, mbedtls_x509_crt *issuer) {
    size_t hash_len;
    unsigned char hash[MBEDTLS_MD_MAX_SIZE];
    mbedtls_md_type_t md = cert->MBEDTLS_PRIVATE(sig_md);
#if !defined(MBEDTLS_USE_PSA_CRYPTO)
    const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md);
    hash_len = mbedtls_md_get_size(md_info);
    if(mbedtls_md(md_info, cert->tbs.p, cert->tbs.len, hash) != 0)
        return false;
#else
    if(psa_hash_compute(mbedtls_md_psa_alg_from_type(md), cert->tbs.p,
                        cert->tbs.len, hash, sizeof(hash), &hash_len) != PSA_SUCCESS)
        return false;
#endif
    const mbedtls_x509_buf *sig = &cert->MBEDTLS_PRIVATE(sig);
    void *sig_opts = cert->MBEDTLS_PRIVATE(sig_opts);
    mbedtls_pk_type_t pktype = cert->MBEDTLS_PRIVATE(sig_pk);
    return (mbedtls_pk_verify_ext(pktype, sig_opts, &issuer->pk, md,
                                  hash, hash_len, sig->p, sig->len) == 0);
}

static UA_StatusCode
mbedtlsVerifyChain(UA_CertificateGroup *cg, MemoryCertStore *ctx, mbedtls_x509_crt *stack,
                   mbedtls_x509_crt **old_issuers, mbedtls_x509_crt *cert, int depth) {
    /* Maxiumum chain length */
    if(depth == UA_MBEDTLS_MAX_CHAIN_LENGTH)
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;


    /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is
     * returned only if all possible chains are incomplete. */
    mbedtls_x509_crt *issuer = NULL;
    UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    while(ret != UA_STATUSCODE_GOOD) {
        /* Find the issuer. This can return the same certificate if it is
         * self-signed (subject == issuer). We come back here to try a different
         * "path" if a subsequent verification fails. */
        issuer = mbedtlsFindNextIssuer(ctx, stack, cert, issuer);
        if(!issuer)
            break;

        /* Verification Step: Certificate Usage
         * Can the issuer act as CA? Omit for self-signed leaf certificates. */
        if((depth > 0 || issuer != cert) && !mbedtlsCheckCA(issuer)) {
            ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED;
            continue;
        }

        /* Verification Step: Signature */
        if(!mbedtlsCheckSignature(cert, issuer)) {
            ret = UA_STATUSCODE_BADCERTIFICATEINVALID;  /* Wrong issuer, try again */
            continue;
        }

        /* The certificate is self-signed. We have arrived at the top of the
         * chain. We check whether the certificate is trusted below. This is the
         * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED.
         * This signals that the chain is complete (but can be still
         * untrusted).
         *
         * Break here as we have reached the end of the chain. Omit the
         * Revocation Check for self-signed certificates. */
        if(issuer == cert || mbedtlsSameBuf(&cert->tbs, &issuer->tbs)) {
            ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
            break;
        }

        /* Verification Step: Revocation Check */
        ret = mbedtlsCheckRevoked(cg, ctx, cert);
        if(depth > 0) {
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED)
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED;
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN)
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
        }
        if(ret != UA_STATUSCODE_GOOD)
            continue;

        /* Detect (endless) loops of issuers */
        for(int i = 0; i < depth; i++) {
            if(old_issuers[i] == issuer)
                return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
        }
        old_issuers[depth] = issuer;

        /* We have found the issuer certificate used for the signature. Recurse
         * to the next certificate in the chain (verify the current issuer). */
        ret = mbedtlsVerifyChain(cg, ctx, stack, old_issuers, issuer, depth + 1);
    }

    /* The chain is complete, but we haven't yet identified a trusted
     * certificate "on the way down". Can we trust this certificate? */
    if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) {
        for(mbedtls_x509_crt *t = &ctx->trustedCertificates; t; t = t->next) {
            if(mbedtlsSameBuf(&cert->tbs, &t->tbs)) {
                ret = UA_STATUSCODE_GOOD;
                break;
            }
        }
    }

    if(ret == UA_STATUSCODE_GOOD) {
        /* Verification Step: Validity Period */
        if(mbedtls_x509_time_is_future(&cert->valid_from) ||
        mbedtls_x509_time_is_past(&cert->valid_to))
            return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID :
                UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID;
    }

    return ret;
}

/* This follows Part 6, 6.1.3 Determining if a Certificate is trusted.
 * It defines a sequence of steps for certificate verification. */
static UA_StatusCode
verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
    /* Check parameter */
    if (certGroup == NULL || certGroup->context == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context->reloadRequired) {
        UA_StatusCode retval = reloadCertificates(certGroup);
        if(retval != UA_STATUSCODE_GOOD) {
            return retval;
        }
        context->reloadRequired = false;
    }

    /* Verification Step: Certificate Structure
     * This parses the entire certificate chain contained in the bytestring. */
    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data,
                                         certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    /* Verification Step: Certificate Usage
     * Check whether the certificate is a User certificate or a CA certificate.
     * Refer the test case CTT/Security/Security Certificate Validation/029.js
     * for more details. */
    if(mbedtlsCheckCA(&cert)) {
        mbedtls_x509_crt_free(&cert);
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    }

    /* These steps are performed outside of this method.
     * Because we need the server or client context.
     * - Security Policy
     * - Host Name
     * - URI */

    /* Verification Step: Build Certificate Chain
     * We perform the checks for each certificate inside. */
    mbedtls_x509_crt *old_issuers[UA_MBEDTLS_MAX_CHAIN_LENGTH];
    UA_StatusCode ret = mbedtlsVerifyChain(certGroup, context, &cert, old_issuers, &cert, 0);
    mbedtls_x509_crt_free(&cert);
    return ret;
}

static UA_StatusCode
MemoryCertStore_verifyCertificate(UA_CertificateGroup *certGroup,
                                  const UA_ByteString *certificate) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = verifyCertificate(certGroup, certificate);
    if(retval != UA_STATUSCODE_GOOD) {
        if(MemoryCertStore_addToRejectedList(certGroup, certificate) != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                           "Could not append certificate to rejected list");
        }
    }
    return retval;
}

UA_StatusCode
UA_CertificateGroup_Memorystore(UA_CertificateGroup *certGroup,
                                UA_NodeId *certificateGroupId,
                                const UA_TrustListDataType *trustList,
                                const UA_Logger *logger,
                                const UA_KeyValueMap *params) {

    if(certGroup == NULL || certificateGroupId == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Clear if the plugin is already initialized */
    if(certGroup->clear)
        certGroup->clear(certGroup);

    UA_NodeId_copy(certificateGroupId, &certGroup->certificateGroupId);
    certGroup->logging = logger;

    certGroup->getTrustList = MemoryCertStore_getTrustList;
    certGroup->setTrustList = MemoryCertStore_setTrustList;
    certGroup->addToTrustList = MemoryCertStore_addToTrustList;
    certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
    certGroup->getRejectedList = MemoryCertStore_getRejectedList;
    certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
    certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
    certGroup->clear = MemoryCertStore_clear;

    /* Set PKI Store context data */
    MemoryCertStore *context = (MemoryCertStore *)UA_calloc(1, sizeof(MemoryCertStore));
    if(!context) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }
    certGroup->context = context;
    /* Default values */
    context->maxTrustListSize = 65535;
    context->maxRejectedListSize = 100;

    if(params) {
        const UA_UInt32 *maxTrustListSize = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);

        const UA_UInt32 *maxRejectedListSize = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);

        if(maxTrustListSize) {
            context->maxTrustListSize = *maxTrustListSize;
        }

        if(maxRejectedListSize) {
            context->maxRejectedListSize = *maxRejectedListSize;
        }
    }

    UA_TrustListDataType_add(trustList, &context->trustList);
    reloadCertificates(certGroup);

    return UA_STATUSCODE_GOOD;

cleanup:
    certGroup->clear(certGroup);
    return retval;
}

#if MBEDTLS_VERSION_NUMBER < 0x03040000

static const unsigned char *
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
    if(l2 == 0)
        return s1;
    if(l1 < l2)
        return NULL;
    size_t limit = l1 - l2 + 1;
    for(size_t i = 0; i < limit; ++i) {
        if(s1[i] == s2[0]) {
            if(memcmp(s1 + i, s2, l2) == 0)
                return s1 + i;
        }
    }
    return NULL;
}

#endif

UA_StatusCode
UA_CertificateUtils_verifyApplicationUri(const UA_ByteString *certificate,
                                         const UA_String *applicationURI) {
    /* Parse the certificate */
    mbedtls_x509_crt remoteCertificate;
    mbedtls_x509_crt_init(&remoteCertificate);

    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

#if MBEDTLS_VERSION_NUMBER >= 0x03040000
    /* Get the Subject Alternative Name and compare */
    mbedtls_x509_subject_alternative_name san;
    mbedtls_x509_sequence *cur = &remoteCertificate.subject_alt_names;
    retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
    for(; cur; cur = cur->next) {
        int res = mbedtls_x509_parse_subject_alt_name(&cur->buf, &san);
        if(res != 0)
            continue;
        if(san.type != MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER) {
            mbedtls_x509_free_subject_alt_name(&san);
            continue;
        }

        UA_String uri = {san.san.unstructured_name.len, san.san.unstructured_name.p};
        UA_Boolean found = UA_String_equal(&uri, applicationURI);
        mbedtls_x509_free_subject_alt_name(&san);
        if(found) {
            retval = UA_STATUSCODE_GOOD;
            break;
        }
    }
#else
    /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
     * of the Alternative Subject Name. Instead test whether the URI-string is
     * present in the v3_ext field in general. */
    if(UA_Bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
                  applicationURI->data, applicationURI->length) == NULL)
        retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
#endif

    mbedtls_x509_crt_free(&remoteCertificate);
    return retval;
}

UA_StatusCode
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
                                      UA_DateTime *expiryDateTime) {
    mbedtls_x509_crt publicKey;
    mbedtls_x509_crt_init(&publicKey);

    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_DateTimeStruct ts;
    ts.year = (UA_Int16)publicKey.valid_to.year;
    ts.month = (UA_UInt16)publicKey.valid_to.mon;
    ts.day = (UA_UInt16)publicKey.valid_to.day;
    ts.hour = (UA_UInt16)publicKey.valid_to.hour;
    ts.min = (UA_UInt16)publicKey.valid_to.min;
    ts.sec = (UA_UInt16)publicKey.valid_to.sec;
    ts.milliSec = 0;
    ts.microSec = 0;
    ts.nanoSec = 0;
    *expiryDateTime = UA_DateTime_fromStruct(ts);
    mbedtls_x509_crt_free(&publicKey);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
                                   UA_String *subjectName) {
    mbedtls_x509_crt publicKey;
    mbedtls_x509_crt_init(&publicKey);

    mbedtls_x509_crl crl;
    mbedtls_x509_crl_init(&crl);

    char buf[1024];
    int res = 0;
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
    if(retval == UA_STATUSCODE_GOOD) {
        res = mbedtls_x509_dn_gets(buf, 1024, &publicKey.subject);
        mbedtls_x509_crt_free(&publicKey);
    } else {
        retval = UA_mbedTLS_LoadCrl(certificate, &crl);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        res = mbedtls_x509_dn_gets(buf, 1024, &crl.issuer);
        mbedtls_x509_crl_free(&crl);
    }

    if(res < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_String tmp = {(size_t)res, (UA_Byte*)buf};
    return UA_String_copy(&tmp, subjectName);
}

UA_StatusCode
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
                                  UA_String *thumbprint){
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(certificate == NULL || thumbprint->length != (UA_SHA1_LENGTH * 2))
        return UA_STATUSCODE_BADINTERNALERROR;

    // prepare temporary to hold the binary thumbprint
    UA_Byte buf[UA_SHA1_LENGTH];
    UA_ByteString thumbpr = {
        /*.length =*/ sizeof(buf),
        /*.data =*/ buf
    };

    retval = mbedtls_thumbprint_sha1(certificate, &thumbpr);

    // convert to hexadecimal string representation
    size_t t = 0u;
    for (size_t i = 0u; i < thumbpr.length; i++) {
        UA_Byte shift = 4u;
        // byte consists of two nibbles: AAAABBBB
        const UA_Byte curByte = thumbpr.data[i];
        // convert AAAA first then BBBB
        for(size_t n = 0u; n < 2u; n++) {
            UA_Byte curNibble = (curByte >> shift) & 0x0Fu;
            if(curNibble >= 10u)
                thumbprint->data[t++] = (65u + (curNibble - 10u));  // 65 == 'A'
            else
                thumbprint->data[t++] = (48u + curNibble);          // 48 == '0'
            shift -= 4u;
        }
    }

    return retval;
}

UA_StatusCode
UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
                               size_t *keySize){
    mbedtls_x509_crt publicKey;
    mbedtls_x509_crt_init(&publicKey);

    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(!mbedtls_pk_can_do(&publicKey.pk, MBEDTLS_PK_RSA)) {
        mbedtls_x509_crt_free(&publicKey);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    mbedtls_rsa_context *rsa = mbedtls_pk_rsa(publicKey.pk);

#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    *keySize = rsa->len * 8;
#else
    *keySize = mbedtls_rsa_get_len(rsa) * 8;
#endif
    mbedtls_x509_crt_free(&publicKey);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
                                      const UA_ByteString *certificate2) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    mbedtls_x509_crt cert1;
    mbedtls_x509_crt cert2;
    mbedtls_x509_csr csr1;
    mbedtls_x509_csr csr2;
    mbedtls_mpi N1, E1;
    mbedtls_mpi N2, E2;

    UA_ByteString data1 = UA_mbedTLS_CopyDataFormatAware(certificate1);
    UA_ByteString data2 = UA_mbedTLS_CopyDataFormatAware(certificate2);

    mbedtls_x509_crt_init(&cert1);
    mbedtls_x509_crt_init(&cert2);
    mbedtls_x509_csr_init(&csr1);
    mbedtls_x509_csr_init(&csr2);
    mbedtls_mpi_init(&N1);
    mbedtls_mpi_init(&E1);
    mbedtls_mpi_init(&N2);
    mbedtls_mpi_init(&E2);

    int mbedErr = mbedtls_x509_crt_parse(&cert1, data1.data, data1.length);
    if(mbedErr) {
        /* Try to load as a csr */
        mbedErr = mbedtls_x509_csr_parse(&csr1, data1.data, data1.length);
        if(mbedErr) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
    }

    mbedErr = mbedtls_x509_crt_parse(&cert2, data2.data, data2.length);
    if(mbedErr) {
        /* Try to load as a csr */
        mbedErr = mbedtls_x509_csr_parse(&csr2, data2.data, data2.length);
        if(mbedErr) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
    }

#if MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_pk_context pk1 = cert1.pk.pk_info ? cert1.pk : csr1.pk;
    mbedtls_pk_context pk2 = cert2.pk.pk_info ? cert2.pk : csr2.pk;
#else
    mbedtls_pk_context pk1 = cert1.pk_raw.p ? cert1.pk : csr1.pk;
    mbedtls_pk_context pk2 = cert2.pk_raw.p ? cert2.pk : csr2.pk;
#endif

    if(!mbedtls_pk_rsa(pk1) || !mbedtls_pk_rsa(pk2)) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(!mbedtls_pk_can_do(&pk1, MBEDTLS_PK_RSA) &&
       !mbedtls_pk_can_do(&pk2, MBEDTLS_PK_RSA)) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

#if MBEDTLS_VERSION_NUMBER < 0x02070000
    N1 = mbedtls_pk_rsa(pk1)->N;
    E1 = mbedtls_pk_rsa(pk1)->E;
    N2 = mbedtls_pk_rsa(pk2)->N;
    E2 = mbedtls_pk_rsa(pk2)->E;
#else
    if(mbedtls_rsa_export(mbedtls_pk_rsa(pk1), &N1, NULL, NULL, NULL, &E1) != 0) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }
    if(mbedtls_rsa_export(mbedtls_pk_rsa(pk2), &N2, NULL, NULL, NULL, &E2) != 0) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }
#endif

    if(mbedtls_mpi_cmp_mpi(&N1, &N2) || mbedtls_mpi_cmp_mpi(&E1, &E2))
        retval = UA_STATUSCODE_BADNOMATCH;

cleanup:
    mbedtls_mpi_free(&N1);
    mbedtls_mpi_free(&E1);
    mbedtls_mpi_free(&N2);
    mbedtls_mpi_free(&E2);
    mbedtls_x509_crt_free(&cert1);
    mbedtls_x509_crt_free(&cert2);
    mbedtls_x509_csr_free(&csr1);
    mbedtls_x509_csr_free(&csr2);
    UA_ByteString_clear(&data1);
    UA_ByteString_clear(&data2);

    return retval;
}

UA_StatusCode
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
                                 const UA_ByteString *privateKey) {
    mbedtls_x509_crt cert;
    mbedtls_pk_context pk;

    mbedtls_x509_crt_init(&cert);
    mbedtls_pk_init(&pk);

    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = (UA_mbedTLS_LoadPrivateKey(privateKey, &pk, NULL)? UA_STATUSCODE_BADSECURITYCHECKSFAILED : UA_STATUSCODE_GOOD);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Verify the private key matches the public key in the certificate */
    if(!mbedtls_pk_can_do(&pk, mbedtls_pk_get_type(&cert.pk))) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto cleanup;
    }

    /* Check if the public key from the certificate matches the private key */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    if(mbedtls_pk_check_pair(&cert.pk, &pk) != 0) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }
#else
    if(mbedtls_pk_check_pair(&cert.pk, &pk, mbedtls_entropy_func, NULL) != 0) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }
#endif

cleanup:
    mbedtls_pk_free(&pk);
    mbedtls_x509_crt_free(&cert);

    return retval;
}

UA_StatusCode
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);

    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = mbedtlsCheckCA(&cert) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOMATCH;

cleanup:
    mbedtls_x509_crt_free(&cert);

    return retval;
}

UA_StatusCode
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
                                      const UA_ByteString password,
                                      UA_ByteString *outDerKey) {
    if(!outDerKey)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (privateKey.length == 0) {
        *outDerKey = UA_BYTESTRING_NULL;
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Already in DER format -> return verbatim.
     * DER-encoded keys start with ASN.1 SEQUENCE tag (0x30). PEM-encoded keys
     * start with "-----BEGIN" (0x2D). Check only the tag byte to handle both
     * short-form (< 128 bytes) and long-form length encodings. */
    if(privateKey.length > 1 && privateKey.data[0] == 0x30)
        return UA_ByteString_copy(&privateKey, outDerKey);

    /* Create a null-terminated string */
    UA_ByteString nullTerminatedKey = UA_mbedTLS_CopyDataFormatAware(&privateKey);
    if(nullTerminatedKey.length != privateKey.length + 1)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Create the private-key context */
    mbedtls_pk_context ctx;
    mbedtls_pk_init(&ctx);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
                                   nullTerminatedKey.length,
                                   password.data, password.length);
#else
    mbedtls_entropy_context entropy;
    mbedtls_entropy_init(&entropy);
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
                                   nullTerminatedKey.length,
                                   password.data, password.length,
                                   mbedtls_entropy_func, &entropy);
    mbedtls_entropy_free(&entropy);
#endif
    UA_ByteString_clear(&nullTerminatedKey);
    if(err != 0) {
        mbedtls_pk_free(&ctx);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    /* Write the DER-encoded key into a local buffer */
    unsigned char buf[1 << 14];
    int written = mbedtls_pk_write_key_der(&ctx, buf, sizeof(buf));
    if(written <= 0) {
        mbedtls_pk_free(&ctx);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }
    size_t pos = (size_t)written;

    /* Allocate memory */
    UA_StatusCode res = UA_ByteString_allocBuffer(outDerKey, pos);
    if(res != UA_STATUSCODE_GOOD) {
        mbedtls_pk_free(&ctx);
        return res;
    }

    /* Copy to the output */
    memcpy(outDerKey->data, &buf[sizeof(buf) - pos], pos);
    mbedtls_pk_free(&ctx);
    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_common.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2022 (c) Wind River Systems, Inc.
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Noel Graf)
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)

#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/hmac.h>
#include <openssl/aes.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/ecdsa.h>
#include <openssl/kdf.h>

#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
#include <openssl/core_names.h>
#endif


#define SHA1_DIGEST_LENGTH 20          /* 160 bits */
#define RSA_DECRYPT_BUFFER_LENGTH 2048 /* bytes */

/* Cast to prevent warnings in LibreSSL */
#define SHA256EVP() ((EVP_MD *)(uintptr_t)EVP_sha256())

/** P_SHA256 Context */
typedef struct UA_Openssl_P_SHA256_Ctx_ {
    size_t  seedLen;
    size_t  secretLen;
    UA_Byte   A[32]; /* 32 bytes of SHA256 output */
    /*
    char seed[seedLen];
    char secret[secretLen]; */
} UA_Openssl_P_SHA256_Ctx;

#define UA_Openssl_P_SHA256_SEED(ctx)   ((ctx)->A+32)
#define UA_Openssl_P_SHA256_SECRET(ctx) ((ctx)->A+32+(ctx)->seedLen)

/** P_SHA1 Context */
typedef struct UA_Openssl_P_SHA1_Ctx_ {
    size_t  seedLen;
    size_t  secretLen;
    UA_Byte A[SHA1_DIGEST_LENGTH];  /* 20 bytes of SHA1 output */
    /*
    char seed[seedLen];
    char secret[secretLen]; */
} UA_Openssl_P_SHA1_Ctx;

#define UA_Openssl_P_SHA1_SEED(ctx)   ((ctx)->A + SHA1_DIGEST_LENGTH)
#define UA_Openssl_P_SHA1_SECRET(ctx) ((ctx)->A + SHA1_DIGEST_LENGTH +(ctx)->seedLen)

void
UA_Openssl_Init(void) {
    /* VxWorks7 has initialized the openssl. */
#ifndef __VXWORKS__
    static UA_Int16 bInit = 0;
    if(bInit == 1)
        return;
#if defined(OPENSSL_API_COMPAT) && (OPENSSL_API_COMPAT < 0x10100000L)
    /* only needed, if OpenSSL < V1.1 */
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();
#endif
    bInit = 1;
#endif
}

static int UA_OpenSSL_RSA_Key_Size(EVP_PKEY * key){
#if(OPENSSL_VERSION_NUMBER >= 0x30000000L)
    return EVP_PKEY_get_size(key);
#else
    return RSA_size(get_pkey_rsa(key));
#endif
}

/* UA_copyCertificate - allocate the buffer, copy the certificate and add a NULL
 * to the end */

UA_StatusCode
UA_copyCertificate(UA_ByteString * dst, const UA_ByteString * src) {
    UA_StatusCode retval = UA_ByteString_allocBuffer(dst, src->length + 1);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    (void) memcpy(dst->data, src->data, src->length);
    dst->data[dst->length - 1] = '\0';
    dst->length--;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_OpenSSL_RSA_Public_Verify(const UA_ByteString *message,
                             const EVP_MD *evpMd, X509 *publicKeyX509,
                             UA_Int16 padding, const UA_ByteString *signature) {
    EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
    if(!mdctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    EVP_PKEY *evpPublicKey = X509_get_pubkey(publicKeyX509);
    if(!evpPublicKey) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    EVP_PKEY_CTX *evpKeyCtx;
    int opensslRet = EVP_DigestVerifyInit(mdctx, &evpKeyCtx, evpMd,
                                          NULL, evpPublicKey);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_PKEY_CTX_set_rsa_padding(evpKeyCtx, padding);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(padding == RSA_PKCS1_PSS_PADDING) {
        opensslRet = EVP_PKEY_CTX_set_rsa_pss_saltlen(evpKeyCtx, RSA_PSS_SALTLEN_DIGEST);
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(evpKeyCtx, SHA256EVP());
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    opensslRet = EVP_DigestVerifyUpdate(mdctx, message->data, message->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_DigestVerifyFinal(mdctx, signature->data, signature->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

errout:
    if(evpPublicKey)
        EVP_PKEY_free(evpPublicKey);
    if(mdctx)
        EVP_MD_CTX_destroy(mdctx);
    return ret;
}

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(const UA_ByteString *msg,
                                       X509 *publicKeyX509,
                                       const UA_ByteString *signature) {
    return UA_OpenSSL_RSA_Public_Verify(msg, EVP_sha256(), publicKeyX509,
                                        RSA_PKCS1_PADDING, signature);
}

UA_StatusCode
UA_OpenSSL_RSA_PSS_SHA256_Verify(const UA_ByteString *msg,
                                 X509 *publicKeyX509,
                                 const UA_ByteString *signature) {
    return UA_OpenSSL_RSA_Public_Verify(msg, EVP_sha256(), publicKeyX509,
                                        RSA_PKCS1_PSS_PADDING, signature);
}

/* Get certificate thumbprint, and allocate the buffer. */

UA_StatusCode
UA_Openssl_X509_GetCertificateThumbprint(const UA_ByteString *certficate,
                                         UA_ByteString *pThumbprint,
                                         bool bThumbPrint) {
    if(bThumbPrint) {
        pThumbprint->length = SHA_DIGEST_LENGTH;
        UA_StatusCode ret = UA_ByteString_allocBuffer(pThumbprint, pThumbprint->length);
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
    } else {
        if(pThumbprint->length != SHA_DIGEST_LENGTH)
            return UA_STATUSCODE_BADINTERNALERROR;
    }
    X509 * x509Certificate = UA_OpenSSL_LoadCertificate(certficate, EVP_PKEY_NONE);

    if(x509Certificate == NULL) {
        if(bThumbPrint)
            UA_ByteString_clear(pThumbprint);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(X509_digest(x509Certificate, EVP_sha1(), pThumbprint->data, NULL) != 1) {
        if(bThumbPrint)
            UA_ByteString_clear(pThumbprint);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    X509_free(x509Certificate);
    return UA_STATUSCODE_GOOD;
}

/* Substring search on a (not necessarily null-terminated) UA_String. */
static UA_Boolean
policyUriContains(const UA_String *uri, const char *token) {
    size_t n = strlen(token);
    if(uri->length < n)
        return false;
    for(size_t i = 0; i + n <= uri->length; i++) {
        if(memcmp(uri->data + i, token, n) == 0)
            return true;
    }
    return false;
}

/* OPC UA Part 6 v1.05.07 (SecureChannelEnhancements): hash a certificate (the
 * leaf, DER) with the hash of the policy's elliptic curve - SHA-256 for the
 * nistP256 curve, SHA-384 for nistP384. Used to build the channel-bound
 * CreateSession / ActivateSession SignatureData.
 *
 * This is NOT the OPN-header Certificate thumbprint: that thumbprint uses the
 * policy's CertificateThumbprintAlgorithm (SHA-1 by default) and is produced by
 * makeCertThumbprint / UA_Openssl_X509_GetCertificateThumbprint. The digest
 * here is selected from the policy URI's curve. */
UA_StatusCode
UA_SecurityPolicy_hashCertificate(const UA_SecurityPolicy *policy,
                                  const UA_ByteString *certificate,
                                  UA_ByteString *hash) {
    if(policy == NULL || certificate == NULL || hash == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Select the digest from the policy's elliptic curve, not a fixed
     * algorithm. */
    const EVP_MD *md;
    size_t hashLen;
    if(policyUriContains(&policy->policyUri, "P384")) {
        md = EVP_sha384();
        hashLen = 48;
    } else if(policyUriContains(&policy->policyUri, "P256")) {
        md = EVP_sha256();
        hashLen = 32;
    } else {
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    }

    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(x509 == NULL)
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    UA_StatusCode ret = UA_ByteString_allocBuffer(hash, hashLen);
    if(ret != UA_STATUSCODE_GOOD) {
        X509_free(x509);
        return ret;
    }
    unsigned int len = 0;
    if(X509_digest(x509, md, hash->data, &len) != 1 || len != hashLen) {
        UA_ByteString_clear(hash);
        X509_free(x509);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    X509_free(x509);
    return UA_STATUSCODE_GOOD;
}

/* Backend-agnostic SecurityPolicy properties derived from the policy URI. Kept
 * out of the UA_SecurityPolicy struct (so its layout stays stable across the
 * 1.5 release family); see the #None fallback in ua_securitypolicy_none.c used
 * when no crypto backend is built. */

/* True if the policy requires the OPC UA Part 6 v1.05.07
 * SecureChannelEnhancements behavior (the ECC_nistP256_* policies). */
UA_Boolean
UA_SecurityPolicy_isEnhancedSecurity(const UA_SecurityPolicy *policy) {
    if(!policy)
        return false;
    static const UA_String eccNistP256AesGcm =
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_AesGcm");
    static const UA_String eccNistP256ChaChaPoly =
        UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_ChaChaPoly");
    return UA_String_equal(&policy->policyUri, &eccNistP256AesGcm) ||
           UA_String_equal(&policy->policyUri, &eccNistP256ChaChaPoly);
}

/* In the OPC UA reference stack the SequenceNumber handling depends on a
 * SecurityPolicy property `LegacySequenceNumbers`: false for all ECC policies
 * (and RSA-DH, which open62541 does not implement), true for None / RSA
 * (Basic*, Aes*_RsaOaep/RsaPss). Non-legacy starts the channel SequenceNumber
 * at 0 and wraps UA_UINT32_MAX -> 0; legacy starts at 1 with the "< 1024"
 * rollover. Detected from the policy URI (all ECC URIs carry the "ECC_"
 * fragment). A NULL policy is treated as legacy. */
UA_Boolean
UA_SecurityPolicy_useLegacySequenceNumbers(const UA_SecurityPolicy *policy) {
    if(!policy)
        return true;
    return !policyUriContains(&policy->policyUri, "ECC_");
}

static UA_StatusCode
UA_Openssl_RSA_Private_Decrypt(UA_ByteString *data, EVP_PKEY *privateKey,
                               UA_Int16 padding, UA_Boolean withSha256) {
    if(data == NULL || privateKey == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(privateKey == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    size_t keySize = (size_t) UA_OpenSSL_RSA_Key_Size(privateKey);
    size_t cipherOffset = 0;
    size_t outOffset = 0;
    unsigned char buf[RSA_DECRYPT_BUFFER_LENGTH];
    size_t decryptedBytes;
    EVP_PKEY_CTX * ctx;
    int opensslRet;

    ctx = EVP_PKEY_CTX_new(privateKey, NULL);
    if(ctx == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    opensslRet = EVP_PKEY_decrypt_init(ctx);
    if(opensslRet != 1) {
        EVP_PKEY_CTX_free(ctx);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    opensslRet = EVP_PKEY_CTX_set_rsa_padding(ctx, padding);
    if(opensslRet != 1) {
        EVP_PKEY_CTX_free(ctx);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(withSha256) {
        opensslRet = EVP_PKEY_CTX_set_rsa_oaep_md(ctx, SHA256EVP());
        if(opensslRet != 1)
            return UA_STATUSCODE_BADINTERNALERROR;
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, SHA256EVP());
        if(opensslRet != 1)
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    while(cipherOffset < data->length) {
        decryptedBytes = RSA_DECRYPT_BUFFER_LENGTH;
        opensslRet = EVP_PKEY_decrypt(ctx, buf, &decryptedBytes,
                                       data->data + cipherOffset, keySize);
        if(opensslRet != 1) {
            EVP_PKEY_CTX_free(ctx);
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        }
        (void) memcpy(data->data + outOffset, buf, decryptedBytes);
        cipherOffset += (size_t) keySize;
        outOffset += decryptedBytes;
    }
    data->length = outOffset;
    EVP_PKEY_CTX_free(ctx);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_RSA_Oaep_Decrypt(UA_ByteString *data,
                            EVP_PKEY *privateKey) {
    return UA_Openssl_RSA_Private_Decrypt(data, privateKey,
                                          RSA_PKCS1_OAEP_PADDING, false);
}

UA_StatusCode
UA_Openssl_RSA_Oaep_Sha2_Decrypt(UA_ByteString *data,
                             EVP_PKEY *privateKey) {
    return UA_Openssl_RSA_Private_Decrypt(data, privateKey,
                                          RSA_PKCS1_OAEP_PADDING, true);
}

static UA_StatusCode
UA_Openssl_RSA_Public_Encrypt(const UA_ByteString *message, X509 *publicX509,
                              UA_Int16 padding, size_t paddingSize,
                              UA_ByteString *encrypted, UA_Boolean withSha256) {
    EVP_PKEY_CTX *ctx = NULL;
    int opensslRet;
    UA_StatusCode ret;
    size_t encryptedTextLen = 0;
    size_t dataPos =  0;
    size_t encryptedPos = 0;
    size_t bytesToEncrypt = 0;
    size_t encryptedBlockSize = 0;
    size_t keySize = 0;

    EVP_PKEY *evpPublicKey = X509_get_pubkey(publicX509);
    if(evpPublicKey == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }
    ctx = EVP_PKEY_CTX_new(evpPublicKey, NULL);
    if(ctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }
    opensslRet = EVP_PKEY_encrypt_init(ctx);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    opensslRet = EVP_PKEY_CTX_set_rsa_padding(ctx, padding);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    if(withSha256) {
        opensslRet = EVP_PKEY_CTX_set_rsa_oaep_md(ctx, SHA256EVP());
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, SHA256EVP());
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    /* get the encrypted block size */

    keySize = (size_t) UA_OpenSSL_RSA_Key_Size(evpPublicKey);
    if(keySize == 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    switch(padding) {
        case RSA_PKCS1_OAEP_PADDING:
        case RSA_PKCS1_PADDING:
            if(keySize <= paddingSize) {
                ret = UA_STATUSCODE_BADINTERNALERROR;
                goto errout;
            }
            encryptedBlockSize = keySize - paddingSize;
            break;
        default:
            ret = UA_STATUSCODE_BADNOTSUPPORTED;
            goto errout;
            break;
    }

    /* encrypt in reverse order so that [data] may alias [encrypted] */

    dataPos =  message->length;
    encryptedPos = ((dataPos - 1) / encryptedBlockSize + 1) * keySize;
    bytesToEncrypt = (dataPos - 1) % encryptedBlockSize + 1;
    encryptedTextLen = encryptedPos;

    while(dataPos > 0) {
        size_t outlen = keySize;
        encryptedPos -= keySize;
        dataPos -= bytesToEncrypt;
        opensslRet = EVP_PKEY_encrypt(ctx, encrypted->data + encryptedPos, &outlen,
                                      message->data + dataPos, bytesToEncrypt);

        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        bytesToEncrypt = encryptedBlockSize;
    }
    encrypted->length = encryptedTextLen;

    ret = UA_STATUSCODE_GOOD;
errout:
    if(evpPublicKey != NULL)
        EVP_PKEY_free(evpPublicKey);
    if(ctx != NULL)
        EVP_PKEY_CTX_free (ctx);
    return ret;
}

UA_StatusCode
UA_Openssl_RSA_OAEP_Encrypt(UA_ByteString *data,
                            size_t paddingSize,
                            X509 *publicX509) {
    UA_ByteString message;
    UA_StatusCode ret = UA_ByteString_copy(data, &message);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    ret = UA_Openssl_RSA_Public_Encrypt(&message, publicX509,
                                        RSA_PKCS1_OAEP_PADDING,
                                        paddingSize, data, false);
    UA_ByteString_clear(&message);
    return ret;
}

UA_StatusCode
UA_Openssl_RSA_OAEP_SHA2_Encrypt(UA_ByteString *data,
                                 size_t paddingSize,
                                 X509 *publicX509) {
    UA_ByteString message;
    UA_StatusCode ret = UA_ByteString_copy (data, &message);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    ret = UA_Openssl_RSA_Public_Encrypt(&message, publicX509,
                                        RSA_PKCS1_OAEP_PADDING,
                                        paddingSize, data, true);
    UA_ByteString_clear(&message);
    return ret;
}

static UA_Openssl_P_SHA256_Ctx *
P_SHA256_Ctx_Create(const UA_ByteString *secret,
                    const UA_ByteString *seed) {
    size_t size = (UA_Int32)sizeof(UA_Openssl_P_SHA256_Ctx) +
        secret->length + seed->length;
    UA_Openssl_P_SHA256_Ctx * ctx = (UA_Openssl_P_SHA256_Ctx *)UA_malloc(size);
    if(ctx == NULL)
        return NULL;
    ctx->secretLen = secret->length;
    ctx->seedLen = seed->length;
    memcpy(UA_Openssl_P_SHA256_SEED(ctx), seed->data, seed->length);
    memcpy(UA_Openssl_P_SHA256_SECRET(ctx), secret->data, secret->length);
    /* A(0) = seed
       A(n) = HMAC_HASH(secret, A(n-1)) */

    if(HMAC(EVP_sha256(), secret->data, (int) secret->length, seed->data,
            seed->length, ctx->A, NULL) == NULL) {
        UA_free (ctx);
        return NULL;
    }

    return ctx;
}

static UA_StatusCode
P_SHA256_Hash_Generate(UA_Openssl_P_SHA256_Ctx *ctx,
                       UA_Byte *pHas) {
    /* Calculate P_SHA256(n) = HMAC_SHA256(secret, A(n)+seed) */
    if(HMAC(EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen,
             ctx->A, sizeof(ctx->A) + ctx->seedLen, pHas, NULL) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Calculate A(n) = HMAC_SHA256(secret, A(n-1)) */
    if(HMAC(EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen,
            ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_Random_Key_PSHA256_Derive(const UA_ByteString *secret,
                                     const UA_ByteString *seed,
                                     UA_ByteString *out) {
    size_t keyLen = out->length;
    size_t iter   = keyLen/32 + ((keyLen%32)?1:0);
    size_t bufferLen = iter * 32;
    size_t i;
    UA_StatusCode st;

    UA_Byte * pBuffer = (UA_Byte *) UA_malloc(bufferLen);
    if(pBuffer == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_Openssl_P_SHA256_Ctx *ctx = P_SHA256_Ctx_Create(secret, seed);
    if(ctx == NULL) {
        UA_free(pBuffer);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for(i = 0; i < iter; i++) {
        st = P_SHA256_Hash_Generate(ctx, pBuffer + (i * 32));
        if(st != UA_STATUSCODE_GOOD) {
            UA_free(pBuffer);
            UA_free(ctx);
            return st;
        }
    }

    memcpy(out->data, pBuffer, keyLen);
    UA_free(pBuffer);
    UA_free(ctx);
    return UA_STATUSCODE_GOOD;
}

/* return the key bytes */
UA_StatusCode
UA_Openssl_RSA_Public_GetKeyLength(X509 *publicKeyX509,
                                   UA_Int32 *keyLen) {
    EVP_PKEY * evpKey = X509_get_pubkey(publicKeyX509);
    if(evpKey == NULL)
        return  UA_STATUSCODE_BADINTERNALERROR;
    *keyLen = UA_OpenSSL_RSA_Key_Size(evpKey);
    EVP_PKEY_free(evpKey);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_RSA_Private_GetKeyLength(EVP_PKEY *privateKey,
                                    UA_Int32 *keyLen) {
    if(privateKey == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    *keyLen = UA_OpenSSL_RSA_Key_Size(privateKey);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Openssl_RSA_Private_Sign(const UA_ByteString *message,
                            EVP_PKEY *privateKey,
                            const EVP_MD *evpMd,
                            UA_Int16 padding,
                            UA_ByteString *outSignature) {
    if(privateKey == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    int opensslRet;
    EVP_PKEY_CTX *evpKeyCtx;
    UA_StatusCode ret;

    EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
    if(mdctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    opensslRet = EVP_DigestSignInit(mdctx, &evpKeyCtx, evpMd, NULL, privateKey);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    EVP_PKEY_CTX_set_rsa_padding(evpKeyCtx, padding);
    if(padding == RSA_PKCS1_PSS_PADDING) {
        opensslRet = EVP_PKEY_CTX_set_rsa_pss_saltlen(evpKeyCtx,
                                                      RSA_PSS_SALTLEN_DIGEST); //RSA_PSS_SALTLEN_DIGEST
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(evpKeyCtx, SHA256EVP());
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    opensslRet = EVP_DigestSignUpdate(mdctx, message->data, message->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_DigestSignFinal(mdctx, outSignature->data, &outSignature->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ret = UA_STATUSCODE_GOOD;

errout:
    if(mdctx != NULL)
        EVP_MD_CTX_destroy(mdctx);
    return ret;
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(const UA_ByteString *message,
                                     EVP_PKEY *privateKey,
                                     UA_ByteString *outSignature) {
    return UA_Openssl_RSA_Private_Sign(message, privateKey, EVP_sha256(),
                                       RSA_PKCS1_PADDING , outSignature);
}

UA_StatusCode
UA_Openssl_RSA_PSS_SHA256_Sign(const UA_ByteString *message,
                               EVP_PKEY *privateKey,
                               UA_ByteString *outSignature) {
    return UA_Openssl_RSA_Private_Sign(message, privateKey, EVP_sha256(),
                                       RSA_PKCS1_PSS_PADDING, outSignature);
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature) {
    unsigned char buf[SHA256_DIGEST_LENGTH] = {0};
    UA_ByteString mac = {SHA256_DIGEST_LENGTH, buf};

    if(HMAC(EVP_sha256(), key->data, (int) key->length, message->data, message->length,
            mac.data, (unsigned int *) &mac.length) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(!UA_ByteString_equal(signature, &mac))
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature) {
    if(HMAC(EVP_sha256(), key->data, (int)key->length, message->data, message->length,
            signature->data, (unsigned int *) &(signature->length)) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_OpenSSL_Decrypt(const UA_ByteString *iv,
                   const UA_ByteString *key,
                   const EVP_CIPHER *cipherAlg,
                   UA_ByteString *data  /* [in/out]*/) {
    UA_ByteString    ivCopy    = {0, NULL};
    UA_ByteString    cipherTxt = {0, NULL};
    EVP_CIPHER_CTX * ctx       = NULL;
    UA_StatusCode    ret;
    int              opensslRet;
    int              outLen;
    int              tmpLen;

    /* copy the IV because the AES_cbc_encrypt function overwrites it. */

    ret = UA_ByteString_copy(iv, &ivCopy);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    ret = UA_ByteString_copy(data, &cipherTxt);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    ctx = EVP_CIPHER_CTX_new();
    if(ctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    /* call EVP_* to decrypt */
    opensslRet = EVP_DecryptInit_ex(ctx, cipherAlg, NULL, key->data, ivCopy.data);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    /* EVP_DecryptFinal() will return an error code if padding is enabled
     * and the final block is not correctly formatted.
     */
    EVP_CIPHER_CTX_set_padding(ctx, 0);
    opensslRet = EVP_DecryptUpdate(ctx, data->data, &outLen,
                                   cipherTxt.data, (int) cipherTxt.length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    opensslRet = EVP_DecryptFinal_ex(ctx, data->data + outLen, &tmpLen);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    outLen += tmpLen;
    data->length = (size_t) outLen;
    ret = UA_STATUSCODE_GOOD;

errout:
    UA_ByteString_clear(&ivCopy);
    UA_ByteString_clear(&cipherTxt);
    if(ctx != NULL) {
        EVP_CIPHER_CTX_free(ctx);
    }
    return ret;
}

static UA_StatusCode
UA_OpenSSL_Encrypt(const UA_ByteString * iv,
                   const UA_ByteString * key,
                   const EVP_CIPHER *    cipherAlg,
                   UA_ByteString *       data  /* [in/out]*/) {
    UA_ByteString    ivCopy   = {0, NULL};
    UA_ByteString    plainTxt = {0, NULL};
    EVP_CIPHER_CTX * ctx      = NULL;
    int              opensslRet;
    int              outLen;
    int              tmpLen;

    /* copy the IV because the AES_cbc_encrypt function overwrites it. */
    UA_StatusCode ret = UA_ByteString_copy(iv, &ivCopy);
    if(ret != UA_STATUSCODE_GOOD) {
        goto errout;
    }

    ret = UA_ByteString_copy(data, &plainTxt);
    if(ret != UA_STATUSCODE_GOOD) {
        goto errout;
    }

    ctx = EVP_CIPHER_CTX_new();
    if(ctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    /* call EVP_* to encrypt */

    opensslRet = EVP_EncryptInit_ex(ctx, cipherAlg, NULL, key->data, ivCopy.data);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Disable padding. Padding is done in the stack before calling encryption.
     * Ensure that we have a multiple of the block size */
    if(data->length % (size_t)EVP_CIPHER_CTX_block_size(ctx)) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    opensslRet = EVP_CIPHER_CTX_set_padding(ctx, 0);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Encrypt the data */
    opensslRet = EVP_EncryptUpdate(ctx, data->data, &outLen,
                                    plainTxt.data, (int) plainTxt.length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Encrypt-final does nothing as padding is disabled */
    opensslRet = EVP_EncryptFinal_ex(ctx, data->data + outLen, &tmpLen);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    outLen += tmpLen;
    data->length = (size_t) outLen;
    ret = UA_STATUSCODE_GOOD;

errout:
    UA_ByteString_clear(&ivCopy);
    UA_ByteString_clear(&plainTxt);
    if(ctx != NULL)
        EVP_CIPHER_CTX_free(ctx);
    return ret;
}

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Decrypt(const UA_ByteString * iv,
                               const UA_ByteString * key,
                               UA_ByteString *       data  /* [in/out]*/) {
    return UA_OpenSSL_Decrypt(iv, key, EVP_aes_256_cbc(), data);
}

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Encrypt(const UA_ByteString * iv,
                               const UA_ByteString * key,
                               UA_ByteString *       data  /* [in/out]*/) {
    return UA_OpenSSL_Encrypt(iv, key, EVP_aes_256_cbc(), data);
}

UA_StatusCode
UA_OpenSSL_X509_compare(const UA_ByteString * cert,
                        const X509 *          bcert) {
    X509 * acert = UA_OpenSSL_LoadCertificate(cert, EVP_PKEY_NONE);
    if(acert == NULL) {
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    }
    int opensslRet = X509_cmp(acert, bcert);
    X509_free(acert);

    if(opensslRet == 0)
        return UA_STATUSCODE_GOOD;
    return UA_STATUSCODE_UNCERTAINSUBNORMAL;
}

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(const UA_ByteString * msg,
                                     X509 *                publicKeyX509,
                                     const UA_ByteString * signature) {
    return UA_OpenSSL_RSA_Public_Verify(msg, EVP_sha1(), publicKeyX509,
                                        RSA_PKCS1_PADDING, signature);
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(const UA_ByteString * message,
                                   EVP_PKEY * privateKey,
                                   UA_ByteString *       outSignature) {
    return UA_Openssl_RSA_Private_Sign(message, privateKey, EVP_sha1(),
                                       RSA_PKCS1_PADDING, outSignature);
}

static UA_Openssl_P_SHA1_Ctx *
P_SHA1_Ctx_Create(const UA_ByteString *  secret,
                  const UA_ByteString *  seed) {
    size_t size = (UA_Int32)sizeof(UA_Openssl_P_SHA1_Ctx) + secret->length +
                    seed->length;
    UA_Openssl_P_SHA1_Ctx * ctx = (UA_Openssl_P_SHA1_Ctx *) UA_malloc(size);
    if(ctx == NULL)
        return NULL;

    ctx->secretLen = secret->length;
    ctx->seedLen = seed->length;
    memcpy(UA_Openssl_P_SHA1_SEED(ctx), seed->data, seed->length);
    memcpy(UA_Openssl_P_SHA1_SECRET(ctx), secret->data, secret->length);
    /* A(0) = seed
       A(n) = HMAC_HASH(secret, A(n-1)) */

    if(HMAC(EVP_sha1(), secret->data, (int) secret->length, seed->data,
            seed->length, ctx->A, NULL) == NULL) {
        UA_free(ctx);
        return NULL;
    }

    return ctx;
}

static UA_StatusCode
P_SHA1_Hash_Generate(UA_Openssl_P_SHA1_Ctx * ctx,
                     UA_Byte *               pHas) {
    /* Calculate P_SHA1(n) = HMAC_SHA1(secret, A(n)+seed) */
    if(HMAC(EVP_sha1 (), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen,
            ctx->A, sizeof (ctx->A) + ctx->seedLen, pHas, NULL) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Calculate A(n) = HMAC_SHA1(secret, A(n-1)) */
   if(HMAC(EVP_sha1(), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen,
           ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) {
       return UA_STATUSCODE_BADINTERNALERROR;
   }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_Random_Key_PSHA1_Derive(const UA_ByteString *     secret,
                                   const UA_ByteString *     seed,
                                   UA_ByteString *           out) {
    size_t keyLen     = out->length;
    size_t iter       = keyLen / SHA1_DIGEST_LENGTH + ((keyLen % SHA1_DIGEST_LENGTH)?1:0);
    size_t bufferLen  = iter * SHA1_DIGEST_LENGTH;
    UA_Byte * pBuffer = (UA_Byte *) UA_malloc(bufferLen);
    if(pBuffer == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_Openssl_P_SHA1_Ctx * ctx = P_SHA1_Ctx_Create(secret, seed);
    if(ctx == NULL) {
        UA_free(pBuffer);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for(size_t i = 0; i < iter; i++) {
        UA_StatusCode st =
            P_SHA1_Hash_Generate(ctx, pBuffer + (i * SHA1_DIGEST_LENGTH));
        if(st != UA_STATUSCODE_GOOD) {
            UA_free(pBuffer);
            UA_free(ctx);
            return st;
        }
    }

    memcpy(out->data, pBuffer, keyLen);
    UA_free(pBuffer);
    UA_free(ctx);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Verify(const UA_ByteString *message,
                            const UA_ByteString *key,
                            const UA_ByteString *signature) {
    unsigned char buf[SHA1_DIGEST_LENGTH] = {0};
    UA_ByteString mac = {SHA1_DIGEST_LENGTH, buf};

    if(HMAC(EVP_sha1(), key->data, (int) key->length, message->data, message->length,
            mac.data, (unsigned int *) &mac.length) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(!UA_ByteString_equal(signature, &mac))
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Sign(const UA_ByteString *     message,
                          const UA_ByteString *     key,
                          UA_ByteString *           signature) {
    if(HMAC(EVP_sha1(), key->data, (int)key->length, message->data, message->length,
            signature->data, (unsigned int *) &(signature->length)) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Decrypt(UA_ByteString *       data,
                                 EVP_PKEY * privateKey) {
    return  UA_Openssl_RSA_Private_Decrypt(data, privateKey,
                                           RSA_PKCS1_PADDING, false);
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Encrypt(UA_ByteString * data,
                                 size_t          paddingSize,
                                 X509 *          publicX509) {
    UA_ByteString message;
    UA_StatusCode ret = UA_ByteString_copy(data, &message);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    ret = UA_Openssl_RSA_Public_Encrypt(&message, publicX509,
                                        RSA_PKCS1_PADDING,
                                        paddingSize, data, false);
    UA_ByteString_clear(&message);
    return ret;
}

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Decrypt(const UA_ByteString * iv,
                               const UA_ByteString * key,
                               UA_ByteString *       data  /* [in/out]*/) {
    return UA_OpenSSL_Decrypt(iv, key, EVP_aes_128_cbc(), data);
}

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Encrypt(const UA_ByteString * iv,
                               const UA_ByteString * key,
                               UA_ByteString *       data  /* [in/out]*/) {
    return UA_OpenSSL_Encrypt(iv, key, EVP_aes_128_cbc(), data);
}

#ifdef _WIN32
#define strtok_r strtok_s
#endif

static UA_StatusCode
UA_OpenSSL_X509_AddSubjectAttributes(const UA_String* subject, X509_NAME* name) {
    char *subj = (char *)UA_malloc(subject->length + 1);
    if(!subj)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    memset(subj, 0x00, subject->length + 1);
    strncpy(subj, (char *)subject->data, subject->length);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* split string into tokens */
    char *saveptr;
    char *token = strtok_r(subj, "/,", &saveptr);
    while(token != NULL) {
        /* find delimiter in attribute */
        size_t delim = 0;
        for(size_t idx = 0; idx < strlen(token); idx++) {
            if(token[idx] == '=') {
                delim = idx;
                break;
            }
        }
        if(delim == 0 || delim == strlen(token)-1) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }

        token[delim] = '\0';
        const unsigned char *para = (const unsigned char*)&token[delim+1];

        /* add attribute to X509_NAME */
        int result = X509_NAME_add_entry_by_txt(name, token, MBSTRING_UTF8, para, -1, -1, 0);
        if(!result) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }

        /* get next token */
        token = strtok_r(NULL, "/,", &saveptr);
    }

cleanup:
    UA_free(subj);
    return retval;
}

static UA_StatusCode
UA_OpenSSL_writePrivateKeyDer(EVP_PKEY *key, UA_ByteString *outPrivateKey) {
    unsigned char *p = NULL;
    const int len = i2d_PrivateKey(key, NULL);
    if(len <= 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(UA_ByteString_allocBuffer(outPrivateKey, len) != UA_STATUSCODE_GOOD) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    outPrivateKey->length = len;
    memset(outPrivateKey->data, 0, outPrivateKey->length);
    p = outPrivateKey->data;
    if(i2d_PrivateKey(key, &p) <= 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_OpenSSL_CreateSigningRequest(EVP_PKEY *localPrivateKey,
                                EVP_PKEY **csrLocalPrivateKey,
                                UA_SecurityPolicy *securityPolicy,
                                const UA_String *subjectName,
                                const UA_ByteString *nonce,
                                UA_ByteString *csr,
                                UA_ByteString *newPrivateKey) {
    /* Check parameter */
    if(!securityPolicy || !csr || !localPrivateKey) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    EVP_PKEY_free(*csrLocalPrivateKey);
    /* CSR has already been generated and private key only needs to be set
     * if a new one has been generated. */
    if(newPrivateKey && newPrivateKey->length > 0) {
        /* Set the private key */
        *csrLocalPrivateKey = UA_OpenSSL_LoadPrivateKey(newPrivateKey);
        if(!(*csrLocalPrivateKey))
            return UA_STATUSCODE_BADINTERNALERROR;

        return UA_STATUSCODE_GOOD;
    }

    if(csr && csr->length > 0)
        return UA_STATUSCODE_GOOD;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Get X509 certificate */
    X509 *x509Certificate =
        UA_OpenSSL_LoadCertificate(&securityPolicy->localCertificate, EVP_PKEY_NONE);
    if(!x509Certificate)
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    /* Create X509 certificate request */
    X509_REQ *request = X509_REQ_new();
    if(request == NULL) {
        X509_free(x509Certificate);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Set version in X509 certificate request */
    if(X509_REQ_set_version(request, 0) != 1) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    /* For request extensions they are all packed in a single attribute.
     * We save them in a STACK and add them all at once later. */
    STACK_OF(X509_EXTENSION)*exts = sk_X509_EXTENSION_new_null();
    if(!exts) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    /* Set key usage in CSR context */
    X509_EXTENSION *key_usage_ext = NULL;
    key_usage_ext = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment");
    if(!key_usage_ext) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        sk_X509_EXTENSION_free(exts);
        goto cleanup;
    }
    sk_X509_EXTENSION_push(exts, key_usage_ext);

    /* Add entropy */
    if(nonce && nonce->length > 0) {
        RAND_seed(nonce->data, nonce->length);
    }

    /* Get subject alternate name field from certificate */
    X509_EXTENSION *subject_alt_name_ext = NULL;
    int pos = X509_get_ext_by_NID(x509Certificate, NID_subject_alt_name, -1);
    if(pos >= 0) {
        subject_alt_name_ext = X509_get_ext(x509Certificate, pos);
        if(subject_alt_name_ext) {
            /* Set subject alternate name in CSR context */
            sk_X509_EXTENSION_push(exts, subject_alt_name_ext);
        }
    }

    /* Now we've created the extensions we add them to the request */
    X509_REQ_add_extensions(request, exts);
    sk_X509_EXTENSION_free(exts);
    X509_EXTENSION_free(key_usage_ext);

    /* Get subject from argument or read it from certificate */
    X509_NAME *name = NULL;
    if(subjectName && subjectName->length > 0) {
        name = X509_NAME_new();
        if(!name) {
            retval = UA_STATUSCODE_BADOUTOFMEMORY;
            goto cleanup;
        }
        /* add subject attributes to name */
        if(UA_OpenSSL_X509_AddSubjectAttributes(subjectName, name) != UA_STATUSCODE_GOOD) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            X509_NAME_free(name);
            goto cleanup;
        }
    } else {
        /* Get subject name from certificate */
        X509_NAME *tmpName = X509_get_subject_name(x509Certificate);
        if(!tmpName) {
            retval = UA_STATUSCODE_BADOUTOFMEMORY;
            goto cleanup;
        }
        name = X509_NAME_dup(tmpName);
    }

    /* Set the subject in CSR context */
    if(!X509_REQ_set_subject_name(request, name)) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        X509_NAME_free(name);
        goto cleanup;
    }
    X509_NAME_free(name);

    if(newPrivateKey) {
        int keyType = EVP_PKEY_base_id(localPrivateKey);
        if(keyType == EVP_PKEY_EC) {
            /* Generate a new EC key on the same curve as the local key */
#if(OPENSSL_VERSION_NUMBER >= 0x30000000L)
            char curveName[64];
            size_t curveNameLen = 0;
            if(!EVP_PKEY_get_utf8_string_param(localPrivateKey, "group",
                                               curveName, sizeof(curveName),
                                               &curveNameLen)) {
                retval = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
            *csrLocalPrivateKey = EVP_PKEY_Q_keygen(NULL, NULL, "EC", curveName);
#else
            int nid = EC_GROUP_get_curve_name(
                EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(localPrivateKey)));
            EC_KEY *ecKey = EC_KEY_new_by_curve_name(nid);
            if(!ecKey || !EC_KEY_generate_key(ecKey)) {
                if(ecKey) EC_KEY_free(ecKey);
                retval = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
            *csrLocalPrivateKey = EVP_PKEY_new();
            if(!*csrLocalPrivateKey ||
               !EVP_PKEY_assign_EC_KEY(*csrLocalPrivateKey, ecKey)) {
                if(*csrLocalPrivateKey) EVP_PKEY_free(*csrLocalPrivateKey);
                else EC_KEY_free(ecKey);
                retval = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
#endif
        } else {
            /* Generate a new RSA key */
            size_t keySize = 0;
            UA_CertificateUtils_getKeySize(&securityPolicy->localCertificate, &keySize);
#if(OPENSSL_VERSION_NUMBER >= 0x30000000L)
            *csrLocalPrivateKey = EVP_RSA_gen(keySize);
#else
            BIGNUM *exponent = BN_new();
            *csrLocalPrivateKey = EVP_PKEY_new();
            RSA *rsa = RSA_new();
            if(!*csrLocalPrivateKey || !exponent || !rsa) {
                if(*csrLocalPrivateKey)
                    EVP_PKEY_free(*csrLocalPrivateKey);
                if(exponent)
                    BN_free(exponent);
                if(rsa)
                    RSA_free(rsa);
                retval = UA_STATUSCODE_BADOUTOFMEMORY;
                goto cleanup;
            }

            if(BN_set_word(exponent, RSA_F4) != 1) {
                retval = UA_STATUSCODE_BADINTERNALERROR;
                EVP_PKEY_free(*csrLocalPrivateKey);
                BN_free(exponent);
                RSA_free(rsa);
                goto cleanup;
            }

            if(RSA_generate_key_ex(rsa, (int) keySize, exponent, NULL) != 1) {
                retval = UA_STATUSCODE_BADINTERNALERROR;
                EVP_PKEY_free(*csrLocalPrivateKey);
                BN_free(exponent);
                RSA_free(rsa);
                goto cleanup;
            }

            if(EVP_PKEY_assign_RSA(*csrLocalPrivateKey, rsa) != 1) {
                retval = UA_STATUSCODE_BADINTERNALERROR;
                EVP_PKEY_free(*csrLocalPrivateKey);
                BN_free(exponent);
                RSA_free(rsa);
                goto cleanup;
            }
            BN_free(exponent);
            /* rsa will be freed by pkey */
            rsa = NULL;
#endif  /* end of OPENSSL_VERSION_NUMBER >= 0x30000000L */
        }
        if(!*csrLocalPrivateKey) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
        if(UA_OpenSSL_writePrivateKeyDer(*csrLocalPrivateKey, newPrivateKey) != UA_STATUSCODE_GOOD) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            EVP_PKEY_free(*csrLocalPrivateKey);
            goto cleanup;
        }

        if(!X509_REQ_set_pubkey(request, *csrLocalPrivateKey)) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            EVP_PKEY_free(*csrLocalPrivateKey);
            goto cleanup;
        }

        if(!X509_REQ_sign(request, *csrLocalPrivateKey, EVP_sha256())) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            EVP_PKEY_free(*csrLocalPrivateKey);
            goto cleanup;
        }
    } else {
        /* Set public key in CSR context */
        EVP_PKEY *pubkey = X509_get_pubkey(x509Certificate);
        if(!pubkey) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
        if(!X509_REQ_set_pubkey(request, pubkey)) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            EVP_PKEY_free(pubkey);
            goto cleanup;
        }
        if(!X509_REQ_sign(request, localPrivateKey, EVP_sha256())) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            EVP_PKEY_free(pubkey);
            goto cleanup;
        }
        EVP_PKEY_free(pubkey);
    }

    /* Determine necessary length for CSR buffer */
    const int csrBufferLength = i2d_X509_REQ(request, 0);
    if(csrBufferLength < 0) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* create CSR buffer */
    UA_ByteString_init(csr);
    UA_ByteString_allocBuffer(csr, csrBufferLength);

    /* Create CSR buffer (DER format) */
    char *ptr = (char*)csr->data;
    i2d_X509_REQ(request, (unsigned char**)&ptr);

cleanup:
    X509_free(x509Certificate);
    X509_REQ_free(request);

    return retval;
}

EVP_PKEY *
UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey) {
    if(privateKey->length == 0)
        return NULL;

    EVP_PKEY *result = NULL;
    BIO *bio = NULL;

    bio = BIO_new_mem_buf((void *) privateKey->data, (int) privateKey->length);
    /* Try to read DER encoded private key */
    result = d2i_PrivateKey_bio(bio, NULL);

    if(result == NULL) {
        /* Try to read PEM encoded private key */
        (void)BIO_reset(bio);
        result = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
    }
    BIO_free(bio);

    return result;
}

X509 *
UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate,
                           int keyType) {
    X509 * result = NULL;

    /* Try to decode DER encoded certificate */
    result = UA_OpenSSL_LoadDerCertificate(certificate);

    if(result == NULL) {
        /* Try to decode PEM encoded certificate */
        result = UA_OpenSSL_LoadPemCertificate(certificate);
    }

    if(!result)
        return NULL;

    /* Don't compare */
    if(keyType == EVP_PKEY_NONE)
        return result;

    EVP_PKEY *pkey = X509_get_pubkey(result);
    if(!pkey) {
        X509_free(result);
        return NULL;
    }

    UA_Boolean good = (EVP_PKEY_base_id(pkey) == keyType);
    EVP_PKEY_free(pkey);
    if(!good) {
        X509_free(result);
        return NULL;
    }

    return result;
}

X509 *
UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate) {
    const unsigned char *pData = certificate->data;
    return d2i_X509(NULL, &pData, (long) certificate->length);
}

X509 *
UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate) {
    X509 * result = NULL;

    BIO* bio = NULL;
    bio = BIO_new_mem_buf((void *) certificate->data, (int) certificate->length);
    result = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    BIO_free(bio);

    return result;
}

X509_CRL *
UA_OpenSSL_LoadCrl(const UA_ByteString *crl) {
    X509_CRL * result = NULL;
    const unsigned char *pData = crl->data;

    if(crl->length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files
        result = UA_OpenSSL_LoadDerCrl(crl);
    } else {
        result = UA_OpenSSL_LoadPemCrl(crl);
    }

    return result;
}

X509_CRL *
UA_OpenSSL_LoadDerCrl(const UA_ByteString *crl) {
    const unsigned char *pData = crl->data;
    return d2i_X509_CRL(NULL, &pData, (long) crl->length);
}

X509_CRL *
UA_OpenSSL_LoadPemCrl(const UA_ByteString *crl) {
    X509_CRL * result = NULL;

    BIO* bio = NULL;
    bio = BIO_new_mem_buf((void *) crl->data, (int) crl->length);
    result = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
    BIO_free(bio);

    return result;
}

UA_StatusCode
UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate,
                                UA_ByteString *target,
                                int keyType) {
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, keyType);

    if(!cert) {
        UA_ByteString_init(target);
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    }

    unsigned char *derData = NULL;
    int length = i2d_X509(cert, &derData);
    X509_free(cert);

    if(length > 0) {
        UA_ByteString temp;
        temp.length = (size_t) length;
        temp.data = derData;
        UA_ByteString_copy(&temp, target);
        OPENSSL_free(derData);
        return UA_STATUSCODE_GOOD;
    } else {
        UA_ByteString_init(target);
    }

    return UA_STATUSCODE_BADINVALIDARGUMENT;
}

#endif

#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
static UA_StatusCode
UA_OpenSSL_ECDH(const int nid,
                EVP_PKEY * keyPairLocal,
                const UA_ByteString * keyPublicRemote,
                UA_ByteString * sharedSecretOut) {
    EVP_PKEY_CTX * pctx = NULL;
    EVP_PKEY_CTX * kctx = NULL;
    EVP_PKEY * remotePubKey = NULL;
    EVP_PKEY * params = NULL;
    UA_ByteString keyPublicRemoteEncoded = UA_BYTESTRING_NULL;

    /* We need one additional byte of memory for the encoding */
    UA_StatusCode ret = UA_ByteString_allocBuffer(&keyPublicRemoteEncoded,
                                                  keyPublicRemote->length+1);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    /* Set the encoding to 0x04 (uncompressed) and copy the public key */
    keyPublicRemoteEncoded.data[0] = 0x04;
    memcpy(&keyPublicRemoteEncoded.data[1], keyPublicRemote->data,
           keyPublicRemote->length);

    remotePubKey = EVP_PKEY_new();
    if(remotePubKey == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
    if(pctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    if(EVP_PKEY_paramgen_init(pctx) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_paramgen(pctx, &params) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_copy_parameters(remotePubKey, params) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

#if defined(LIBRESSL_VERSION_NUMBER)
    /* LibreSSL does currently not support TLS-encoded point APIs required for ECDH */
    ret = UA_STATUSCODE_BADNOTSUPPORTED;
    goto errout;
#elif(OPENSSL_VERSION_NUMBER >= 0x30000000L)
    if(EVP_PKEY_set1_encoded_public_key(remotePubKey, keyPublicRemoteEncoded.data,
                                        keyPublicRemoteEncoded.length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
#else
    if(EVP_PKEY_set1_tls_encodedpoint(remotePubKey, keyPublicRemoteEncoded.data,
                                      keyPublicRemoteEncoded.length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
#endif

    kctx = EVP_PKEY_CTX_new(keyPairLocal, NULL);
    if(kctx == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_derive_init(kctx) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_derive_set_peer(kctx, remotePubKey) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_derive(kctx, NULL, &sharedSecretOut->length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ret = UA_ByteString_allocBuffer(sharedSecretOut, sharedSecretOut->length);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    if(EVP_PKEY_derive(kctx, sharedSecretOut->data, &sharedSecretOut->length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

errout:
    UA_ByteString_clear(&keyPublicRemoteEncoded);
    EVP_PKEY_free(remotePubKey);
    EVP_PKEY_CTX_free(pctx);
    EVP_PKEY_CTX_free(kctx);
    EVP_PKEY_free(params);

    return ret;
}

static UA_StatusCode
UA_OpenSSL_ECC_GenerateSalt(const size_t L,
                            const UA_ByteString * label,
                            const UA_ByteString * key1,
                            const UA_ByteString * key2,
                            UA_ByteString * salt) {
    if(salt == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t saltLen = sizeof(uint16_t) + label->length + key1->length + key2->length;
    if(UA_STATUSCODE_GOOD != UA_ByteString_allocBuffer(salt, saltLen))
        return UA_STATUSCODE_BADOUTOFMEMORY;

    salt->data[0] = (L) & 0xFF;
    salt->data[1] = (L >> 8) & 0xFF;

    UA_Byte * saltPtr = &salt->data[2];

    memcpy(saltPtr, label->data, label->length);
    saltPtr += label->length;
    memcpy(saltPtr, key1->data, key1->length);
    saltPtr += key1->length;
    memcpy(saltPtr, key2->data, key2->length);

    return UA_STATUSCODE_GOOD;
}

#if(OPENSSL_VERSION_NUMBER >= 0x30000000L)
static UA_StatusCode
UA_OpenSSL_HKDF(char * hashAlgorithm,
                const UA_ByteString * ikm,
                const UA_ByteString * salt,
                const UA_ByteString * info,
                UA_ByteString * out) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    EVP_KDF * kdf = NULL;
    EVP_KDF_CTX * kctx = NULL;
    OSSL_PARAM params[5];
    OSSL_PARAM * p = params;

    kdf = EVP_KDF_fetch(NULL, "HKDF", NULL);
    if(kdf == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    kctx = EVP_KDF_CTX_new(kdf);
    if(kctx == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, hashAlgorithm, strlen(hashAlgorithm));
    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, ikm->data, ikm->length);
    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, info->data, info->length);
    *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, salt->data, salt->length);
    *p = OSSL_PARAM_construct_end();

    if(EVP_KDF_derive(kctx, out->data, out->length, params) <= 0) {
        ERR_print_errors_fp(stdout);
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

errout:
    EVP_KDF_free(kdf);
    EVP_KDF_CTX_free(kctx);

    return ret;
}

#else

static UA_StatusCode
UA_OpenSSL_HKDF(char * hashAlgorithm,
                const UA_ByteString * ikm,
                const UA_ByteString * salt,
                const UA_ByteString * info,
                UA_ByteString * out) {

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    EVP_PKEY_CTX *pctx = NULL;
    const EVP_MD *md = NULL;

    /* Retrieve the digest pointer */
    md = EVP_get_digestbyname(hashAlgorithm);
    if(md == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
    if(EVP_PKEY_derive_init(pctx) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    if(EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    if(EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt->data, salt->length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    if(EVP_PKEY_CTX_set1_hkdf_key(pctx, ikm->data, ikm->length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    if(EVP_PKEY_CTX_add1_hkdf_info(pctx, info->data, info->length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    if(EVP_PKEY_derive(pctx, out->data, &out->length) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
errout:
    EVP_PKEY_CTX_free(pctx);

    return ret;
}
#endif

UA_StatusCode
UA_OpenSSL_ECC_DeriveKeys(const int curveID, char *hashAlgorithm,
                          const UA_ApplicationType applicationType,
                          EVP_PKEY *localEphemeralKeyPair,
                          const UA_ByteString *key1, const UA_ByteString *key2,
                          UA_ByteString *out) {
#if defined(LIBRESSL_VERSION_NUMBER)
    return UA_STATUSCODE_BADNOTSUPPORTED;
#endif

    UA_ByteString sharedSecret = UA_BYTESTRING_NULL;
    UA_ByteString salt = UA_BYTESTRING_NULL;
    UA_ByteString ikm = UA_BYTESTRING_NULL;
    UA_ByteString ikmPrev = UA_BYTESTRING_NULL;
    UA_ByteString *secret = NULL; /* points to either &sharedSecret or &ikm */

    /* Get the local ephemeral public key to use in comparison. The
     * encoded form begins with a single 0x04 byte (for uncompressed
     * points) followed by the X and Y coordinates. The comparison
     * below uses &keyPubEnc[1] as the start, so the expected length
     * of `key1` is (keyPubEncSize - 1). */
    UA_Byte *keyPubEnc = NULL;
#if(OPENSSL_VERSION_NUMBER >= 0x30000000L)
    size_t keyPubEncSize =
        EVP_PKEY_get1_encoded_public_key(localEphemeralKeyPair, &keyPubEnc);
#else
    size_t keyPubEncSize =
        EVP_PKEY_get1_tls_encodedpoint(localEphemeralKeyPair, &keyPubEnc);
#endif
    if(keyPubEncSize <= 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    size_t expectedKey1Len = keyPubEncSize - 1;

    /* OPC UA Part 6 v1.05.07 §6.8.1 step 2 "Extract" (IKM chaining
     * on renewal): the SecureChannel may prepend the previous IKM
     * accumulator to `key1`. Detect this by checking if `key1` is
     * longer than expected. The prepend length is `key1->length -
     * expectedKey1Len` and the IKM is a chain of XORs with the
     * shared secret. */
    UA_ByteString key1Effective = *key1;
    size_t ikmPrependLength = 0;
    if(key1->length > expectedKey1Len) {
        ikmPrependLength = key1->length - expectedKey1Len;
        ikmPrev.data = (UA_Byte*)(uintptr_t)key1->data;
        ikmPrev.length = ikmPrependLength;
        key1Effective.data += ikmPrependLength;
        key1Effective.length -= ikmPrependLength;
    }

    /* The order of ephemeral public keys (key1 and key2) tells us whether we
     * need to generate the local keys or the remote keys. To figure that out,
     * we compare the public part of localEphemeralKeyPair with key1 and
     * key2. */

    /* Determine the label for salt generation, remote ephemeral public key for
     * ECDH, and info for HKDF */
    UA_ByteString* label = NULL;
    const UA_ByteString * remoteEphPubKey = NULL;
    static UA_String serverLabel = UA_STRING_STATIC("opcua-server");
    static UA_String clientLabel = UA_STRING_STATIC("opcua-client");
    static UA_String sessionLabel = UA_STRING_STATIC("opcua-secret");

    /* (Temporary) measure to signal salt generation for sessions. out should
     * always be allocated before this check, so it shouldn't cause problems. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(out->data[0] == 0x03 && out->data[1] == 0x03 && out->data[2] == 0x04 ) {
        label = &sessionLabel;
        if(applicationType == UA_APPLICATIONTYPE_SERVER) {
            remoteEphPubKey = key2;
        } else {
            remoteEphPubKey = &key1Effective;
        }
    }
    /* Comparing from the second byte since the first byte has 0x04 from the encoding */
    else if(memcmp(&keyPubEnc[1], key1Effective.data, key1Effective.length) == 0) {
        /* Key 1 is local ephemeral public key => generating remote keys */
        remoteEphPubKey = key2;
        if(applicationType == UA_APPLICATIONTYPE_SERVER) {
            label = &clientLabel;
        } else {
            label = &serverLabel;
        }
    }
    else if(memcmp(&keyPubEnc[1], key2->data, key2->length) == 0) {
        /* Key 2 is local ephemeral public key => generating local keys */
        remoteEphPubKey = &key1Effective;
        if(applicationType == UA_APPLICATIONTYPE_SERVER) {
            label = &serverLabel;
        } else {
            label = &clientLabel;
        }
    } else {
        /* invalid */
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Use ECDH to calculate shared secret */
    ret = UA_OpenSSL_ECDH(curveID, localEphemeralKeyPair, remoteEphPubKey, &sharedSecret);
    if(ret != UA_STATUSCODE_GOOD) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* IKM chaining: when the SecureChannel provided a previous
     * accumulator, XOR it with the raw shared secret to form the new
     * IKM. The new IKM is then written back into the prefix slot of
     * `key1` so the SecureChannel can pick it up after this call. */
    if(ikmPrependLength > 0) {
        if(ikmPrev.length != sharedSecret.length) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        UA_StatusCode alloc = UA_ByteString_allocBuffer(&ikm, sharedSecret.length);
        if(alloc != UA_STATUSCODE_GOOD) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        for(size_t i = 0; i < sharedSecret.length; i++)
            ikm.data[i] = (UA_Byte)(ikmPrev.data[i] ^ sharedSecret.data[i]);
        /* Write the new accumulator back into the prefix slot. The
         * SecureChannel reads it from there to update its own
         * channel->currentIKM. */
        memcpy(ikmPrev.data, ikm.data, ikm.length);
        secret = &ikm;
    } else {
        secret = &sharedSecret;
    }

    /* Calculate salt. The order of the (ephemeral public) keys (key1, key2) is
     * reversed because the caller sends [remote, local] for local key
     * computation and [local, remote] for remote key computation. According to
     * 6.8.1., the local salt computation appends the keys in order [local |
     * remote] and the remote salt computation [remote | local]. Therefore, no
     * additional logic is required, reversing the order is sufficient. The
     * `key1` argument here is the un-prefixed nonce (key1Effective) so the
     * salt only contains the actual nonce data. */
    ret = UA_OpenSSL_ECC_GenerateSalt(out->length, label, key2, &key1Effective, &salt);
    if(ret != UA_STATUSCODE_GOOD) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Call HKDF to derive keys */
    /* Salt is given as the info argument (check 6.8.1., tables 66 and 67) */
    ret = UA_OpenSSL_HKDF(hashAlgorithm, secret, &salt, &salt, out);
    if(ret != UA_STATUSCODE_GOOD) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

errout:
    OPENSSL_free(keyPubEnc);
    UA_ByteString_clear(&sharedSecret);
    UA_ByteString_clear(&salt);
    UA_ByteString_clear(&ikm);

    return ret;
}

static UA_StatusCode
UA_OpenSSL_ECC_GenerateKey(const int curveId,
                           EVP_PKEY ** keyPairOut,
                           UA_ByteString * keyPublicEncOut) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    EVP_PKEY_CTX * pctx = NULL;
    EVP_PKEY_CTX * kctx = NULL;
    EVP_PKEY * params = NULL;
    size_t keyPubEncSize = 0;
    UA_Byte * keyPubEnc = NULL;

    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
    if(pctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    if(EVP_PKEY_paramgen_init(pctx) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, curveId) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_paramgen(pctx, &params) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    kctx = EVP_PKEY_CTX_new(params, NULL);
    if(kctx == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_keygen_init(kctx) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(EVP_PKEY_keygen(kctx, keyPairOut) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

#if defined(LIBRESSL_VERSION_NUMBER)
    ret = UA_STATUSCODE_BADNOTSUPPORTED;
    goto errout; /* LibreSSL does currently not support TLS-encoded point APIs
                  * required for ECDH */
#elif(OPENSSL_VERSION_NUMBER >= 0x30000000L)
    keyPubEncSize = EVP_PKEY_get1_encoded_public_key(*keyPairOut, &keyPubEnc);
#else
    keyPubEncSize = EVP_PKEY_get1_tls_encodedpoint(*keyPairOut, &keyPubEnc);
#endif
    if(keyPubEncSize <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    UA_assert(keyPubEncSize-1 == keyPublicEncOut->length);

    /* Omit the first byte (encoding) */
    memcpy(keyPublicEncOut->data, &keyPubEnc[1], keyPubEncSize-1);

errout:
    EVP_PKEY_CTX_free(pctx);
    EVP_PKEY_free(params);
    EVP_PKEY_CTX_free(kctx);
    OPENSSL_free(keyPubEnc);

    return ret;
}

static UA_StatusCode
UA_Openssl_ECDSA_Sign(const UA_ByteString * message,
                      EVP_PKEY * privateKey,
                      const EVP_MD * evpMd,
                      UA_ByteString * outSignature) {
    EVP_MD_CTX * mdctx = NULL;
    int opensslRet = 0;
    EVP_PKEY_CTX * evpKeyCtx = NULL;
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_ByteString signatureEnc = UA_BYTESTRING_NULL;
    ECDSA_SIG* signatureRaw = NULL;
    const BIGNUM * pr = NULL;
    const BIGNUM * ps = NULL;
    size_t sizeEncCoordinate = 0;

    if(privateKey == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    mdctx = EVP_MD_CTX_create();
    if(mdctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    opensslRet = EVP_DigestSignInit(mdctx, &evpKeyCtx, evpMd, NULL, privateKey);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_DigestSignUpdate(mdctx, message->data, message->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Length required for internal computing */
#if(OPENSSL_VERSION_NUMBER >= 0x30000000L)
    signatureEnc.length = EVP_PKEY_get_size(privateKey);
#else
    signatureEnc.length = ECDSA_size(EVP_PKEY_get0_EC_KEY(privateKey));
#endif

    /* Temporary buffer for OpenSSL-internal signature computation */
    ret = UA_ByteString_allocBuffer(&signatureEnc, signatureEnc.length);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    opensslRet = EVP_DigestSignFinal(mdctx, signatureEnc.data, &signatureEnc.length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    // using temp pointer since the function call increments it
    const UA_Byte * ptmpData = signatureEnc.data;

    signatureRaw = d2i_ECDSA_SIG(NULL, &ptmpData, signatureEnc.length);
    if(signatureRaw == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ECDSA_SIG_get0(signatureRaw, &pr, &ps);
    if(pr == NULL || ps == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    sizeEncCoordinate = outSignature->length / 2;
    if(sizeEncCoordinate <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(BN_bn2binpad(pr, outSignature->data, sizeEncCoordinate) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(BN_bn2binpad(ps, outSignature->data + sizeEncCoordinate, sizeEncCoordinate) <= 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

errout:
    EVP_MD_CTX_destroy(mdctx);
    UA_ByteString_clear(&signatureEnc);
    ECDSA_SIG_free(signatureRaw);

    return ret;
}

static UA_StatusCode
UA_Openssl_ECDSA_Verify(const UA_ByteString * message,
                        const EVP_MD * evpMd,
                        X509 * publicKeyX509,
                        const UA_ByteString * signature) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    EVP_MD_CTX *mdctx = NULL;
    BIGNUM *pr = NULL;
    BIGNUM *ps = NULL;
    UA_ByteString signatureEnc = UA_BYTESTRING_NULL;
    ECDSA_SIG *signatureRaw = NULL;
    EVP_PKEY *evpPublicKey = NULL;
    size_t sizeEncCoordinate = 0;

    if(evpMd == EVP_sha256()) {
        sizeEncCoordinate = 32;
    } else if(evpMd == EVP_sha384()) {
        sizeEncCoordinate = 48;
    } else {
        ret = UA_STATUSCODE_BADINVALIDARGUMENT;
        goto errout;
    }

    pr = BN_bin2bn(signature->data, sizeEncCoordinate, NULL);
    ps = BN_bin2bn(signature->data + sizeEncCoordinate, sizeEncCoordinate, NULL);
    if(pr == NULL || ps == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    signatureRaw = ECDSA_SIG_new();
    if(signatureRaw == NULL) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(ECDSA_SIG_set0(signatureRaw, pr, ps) != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    // this call is to find out the length of the encoded signature
    signatureEnc.length = i2d_ECDSA_SIG(signatureRaw, NULL);
    if(signatureEnc.length == 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ret = UA_ByteString_allocBuffer(&signatureEnc, signatureEnc.length);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    // use temp pointer since the function call increments it
    UA_Byte * ptmpData = signatureEnc.data;
    signatureEnc.length = i2d_ECDSA_SIG(signatureRaw, &ptmpData);
    if(signatureEnc.length == 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    mdctx = EVP_MD_CTX_create();
    if(!mdctx) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    evpPublicKey = X509_get_pubkey(publicKeyX509);
    if(!evpPublicKey) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    EVP_PKEY_CTX * evpKeyCtx = NULL;
    int opensslRet = EVP_DigestVerifyInit(mdctx, &evpKeyCtx, evpMd,
                                          NULL, evpPublicKey);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_DigestVerifyUpdate(mdctx, message->data, message->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_DigestVerifyFinal(mdctx, signatureEnc.data, signatureEnc.length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_PKEY_free(evpPublicKey);
    EVP_MD_CTX_destroy(mdctx);
    ECDSA_SIG_free(signatureRaw);
    UA_ByteString_clear(&signatureEnc);

    return ret;
}

UA_StatusCode
UA_OpenSSL_ECC_NISTP256_GenerateKey(EVP_PKEY ** keyPairOut,
                                    UA_ByteString * keyPublicEncOut) {
    return UA_OpenSSL_ECC_GenerateKey(EC_curve_nist2nid("P-256"), keyPairOut,
                                      keyPublicEncOut);
}


UA_StatusCode
UA_OpenSSL_ECC_NISTP384_GenerateKey(EVP_PKEY ** keyPairOut,
                                    UA_ByteString * keyPublicEncOut) {
    return UA_OpenSSL_ECC_GenerateKey(EC_curve_nist2nid("P-384"), keyPairOut,
                                      keyPublicEncOut);
}

UA_StatusCode
UA_OpenSSL_ECC_BRAINPOOLP256R1_GenerateKey(EVP_PKEY ** keyPairOut,
                                            UA_ByteString * keyPublicEncOut) {
    return UA_OpenSSL_ECC_GenerateKey(OBJ_txt2nid("brainpoolP256r1"), keyPairOut,
                                      keyPublicEncOut);
}

UA_StatusCode
UA_OpenSSL_ECC_BRAINPOOLP384R1_GenerateKey(EVP_PKEY ** keyPairOut,
                                            UA_ByteString * keyPublicEncOut) {
    return UA_OpenSSL_ECC_GenerateKey(OBJ_txt2nid("brainpoolP384r1"), keyPairOut,
                                      keyPublicEncOut);
}
UA_StatusCode
UA_Openssl_ECDSA_SHA256_Sign(const UA_ByteString * message,
                             EVP_PKEY * privateKey,
                             UA_ByteString * outSignature) {
    return UA_Openssl_ECDSA_Sign(message, privateKey, EVP_sha256(), outSignature);
}

UA_StatusCode
UA_Openssl_ECDSA_SHA256_Verify(const UA_ByteString * message,
                               X509 * publicKeyX509,
                               const UA_ByteString * signature) {
    return UA_Openssl_ECDSA_Verify(message, EVP_sha256(), publicKeyX509, signature);
}


UA_StatusCode
UA_Openssl_ECDSA_SHA384_Sign(const UA_ByteString * message,
                             EVP_PKEY * privateKey,
                             UA_ByteString * outSignature) {
    return UA_Openssl_ECDSA_Sign(message, privateKey, EVP_sha384(), outSignature);
}

UA_StatusCode
UA_Openssl_ECDSA_SHA384_Verify(const UA_ByteString * message,
                               X509 * publicKeyX509,
                               const UA_ByteString * signature) {
    return UA_Openssl_ECDSA_Verify(message, EVP_sha384(), publicKeyX509, signature);
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA384_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature) {
    unsigned char buf[SHA384_DIGEST_LENGTH] = {0};
    UA_ByteString mac = {SHA384_DIGEST_LENGTH, buf};

    if(HMAC(EVP_sha384(), key->data, (int) key->length, message->data, message->length,
            mac.data, (unsigned int *) &mac.length) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(!UA_ByteString_equal(signature, &mac))
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA384_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature) {
    if(HMAC(EVP_sha384(), key->data, (int)key->length, message->data, message->length,
            signature->data, (unsigned int *) &(signature->length)) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

/* EdDSA Ed25519 Sign/Verify */

UA_StatusCode
UA_OpenSSL_EdDSA_Ed25519_Sign(const UA_ByteString *message,
                              EVP_PKEY *privateKey,
                              UA_ByteString *outSignature) {
    EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
    if(!mdctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DigestSignInit(mdctx, NULL, NULL, NULL, privateKey) != 1)
        goto errout;

    size_t sigLen = outSignature->length;
    if(EVP_DigestSign(mdctx, outSignature->data, &sigLen,
                      message->data, message->length) != 1)
        goto errout;

    outSignature->length = sigLen;
    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_MD_CTX_free(mdctx);
    return ret;
}

UA_StatusCode
UA_OpenSSL_EdDSA_Ed25519_Verify(const UA_ByteString *message,
                                X509 *publicKeyX509,
                                const UA_ByteString *signature) {
    EVP_PKEY *pubKey = X509_get0_pubkey(publicKeyX509);
    if(!pubKey)
        return UA_STATUSCODE_BADINTERNALERROR;

    EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
    if(!mdctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pubKey) != 1)
        goto errout;

    if(EVP_DigestVerify(mdctx, signature->data, signature->length,
                        message->data, message->length) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto errout;
    }

    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_MD_CTX_free(mdctx);
    return ret;
}

/* EdDSA Ed448 Sign/Verify */

UA_StatusCode
UA_OpenSSL_EdDSA_Ed448_Sign(const UA_ByteString *message,
                            EVP_PKEY *privateKey,
                            UA_ByteString *outSignature) {
    EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
    if(!mdctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DigestSignInit(mdctx, NULL, NULL, NULL, privateKey) != 1)
        goto errout;

    size_t sigLen = outSignature->length;
    if(EVP_DigestSign(mdctx, outSignature->data, &sigLen,
                      message->data, message->length) != 1)
        goto errout;

    outSignature->length = sigLen;
    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_MD_CTX_free(mdctx);
    return ret;
}

UA_StatusCode
UA_OpenSSL_EdDSA_Ed448_Verify(const UA_ByteString *message,
                              X509 *publicKeyX509,
                              const UA_ByteString *signature) {
    EVP_PKEY *pubKey = X509_get0_pubkey(publicKeyX509);
    if(!pubKey)
        return UA_STATUSCODE_BADINTERNALERROR;

    EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
    if(!mdctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pubKey) != 1)
        goto errout;

    if(EVP_DigestVerify(mdctx, signature->data, signature->length,
                        message->data, message->length) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto errout;
    }

    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_MD_CTX_free(mdctx);
    return ret;
}

/* X25519 / X448 Key Generation */

UA_StatusCode
UA_OpenSSL_X25519_GenerateKey(EVP_PKEY **keyPairOut,
                              UA_ByteString *keyPublicEncOut) {
    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
    if(!pctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_PKEY_keygen_init(pctx) != 1)
        goto errout;

    if(EVP_PKEY_keygen(pctx, keyPairOut) != 1)
        goto errout;

    /* Get the raw public key (32 bytes for X25519) */
    size_t pubKeyLen = keyPublicEncOut->length;
    if(EVP_PKEY_get_raw_public_key(*keyPairOut, keyPublicEncOut->data, &pubKeyLen) != 1)
        goto errout;

    keyPublicEncOut->length = pubKeyLen;
    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_PKEY_CTX_free(pctx);
    return ret;
}

UA_StatusCode
UA_OpenSSL_X448_GenerateKey(EVP_PKEY **keyPairOut,
                            UA_ByteString *keyPublicEncOut) {
    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X448, NULL);
    if(!pctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_PKEY_keygen_init(pctx) != 1)
        goto errout;

    if(EVP_PKEY_keygen(pctx, keyPairOut) != 1)
        goto errout;

    /* Get the raw public key (56 bytes for X448) */
    size_t pubKeyLen = keyPublicEncOut->length;
    if(EVP_PKEY_get_raw_public_key(*keyPairOut, keyPublicEncOut->data, &pubKeyLen) != 1)
        goto errout;

    keyPublicEncOut->length = pubKeyLen;
    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_PKEY_CTX_free(pctx);
    return ret;
}

/* X25519/X448 ECDH Key Agreement (XDHE) + HKDF Key Derivation */

static UA_StatusCode
UA_OpenSSL_XDHE(int keyType,
                EVP_PKEY *localEphemeralKeyPair,
                const UA_ByteString *remoteEphPubKey,
                UA_ByteString *sharedSecretOut) {
    /* Create remote public key from raw bytes */
    EVP_PKEY *remotePubKey = EVP_PKEY_new_raw_public_key(
        keyType, NULL, remoteEphPubKey->data, remoteEphPubKey->length);
    if(!remotePubKey)
        return UA_STATUSCODE_BADINTERNALERROR;

    EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new(localEphemeralKeyPair, NULL);
    if(!kctx) {
        EVP_PKEY_free(remotePubKey);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_PKEY_derive_init(kctx) <= 0)
        goto errout;

    if(EVP_PKEY_derive_set_peer(kctx, remotePubKey) <= 0)
        goto errout;

    /* Get shared secret size */
    size_t secretLen = 0;
    if(EVP_PKEY_derive(kctx, NULL, &secretLen) <= 0)
        goto errout;

    ret = UA_ByteString_allocBuffer(sharedSecretOut, secretLen);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    if(EVP_PKEY_derive(kctx, sharedSecretOut->data, &sharedSecretOut->length) <= 0) {
        UA_ByteString_clear(sharedSecretOut);
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_PKEY_CTX_free(kctx);
    EVP_PKEY_free(remotePubKey);
    return ret;
}

UA_StatusCode
UA_OpenSSL_XDHE_DeriveKeys(int keyType,
                            const char *hashAlgorithm,
                            UA_ApplicationType applicationType,
                            EVP_PKEY *localEphemeralKeyPair,
                            const UA_ByteString *key1,
                            const UA_ByteString *key2,
                            UA_ByteString *out) {
    UA_ByteString sharedSecret = UA_BYTESTRING_NULL;
    UA_ByteString salt = UA_BYTESTRING_NULL;
    UA_ByteString ikm = UA_BYTESTRING_NULL;
    UA_ByteString ikmPrev = UA_BYTESTRING_NULL;
    UA_ByteString *secret = NULL;

    /* Get the local ephemeral public key for comparison */
    size_t pubKeyLen = 0;
    if(EVP_PKEY_get_raw_public_key(localEphemeralKeyPair, NULL, &pubKeyLen) != 1)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_Byte keyPubEnc[64]; /* Max 56 bytes for X448 */
    if(pubKeyLen > sizeof(keyPubEnc))
        return UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_PKEY_get_raw_public_key(localEphemeralKeyPair, keyPubEnc, &pubKeyLen) != 1)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* OPC UA Part 6 v1.05.07 §6.8.1 step 2 IKM chaining. See the
     * matching comment in UA_OpenSSL_ECC_DeriveKeys. The prepend is
     * detected by `key1` being longer than the expected ephemeral
     * public key length. */
    UA_ByteString key1Effective = *key1;
    size_t ikmPrependLength = 0;
    if(key1->length > pubKeyLen) {
        ikmPrependLength = key1->length - pubKeyLen;
        ikmPrev.data = (UA_Byte*)(uintptr_t)key1->data;
        ikmPrev.length = ikmPrependLength;
        key1Effective.data += ikmPrependLength;
        key1Effective.length -= ikmPrependLength;
    }

    /* Determine label and remote ephemeral public key */
    UA_ByteString *label = NULL;
    const UA_ByteString *remoteEphPubKey = NULL;
    static UA_String serverLabel = UA_STRING_STATIC("opcua-server");
    static UA_String clientLabel = UA_STRING_STATIC("opcua-client");
    static UA_String sessionLabel = UA_STRING_STATIC("opcua-secret");

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(out->data[0] == 0x03 && out->data[1] == 0x03 && out->data[2] == 0x04) {
        label = &sessionLabel;
        if(applicationType == UA_APPLICATIONTYPE_SERVER) {
            remoteEphPubKey = key2;
        } else {
            remoteEphPubKey = &key1Effective;
        }
    } else if(pubKeyLen == key1Effective.length &&
              memcmp(keyPubEnc, key1Effective.data, key1Effective.length) == 0) {
        /* Key 1 is local ephemeral public key => generating remote keys */
        remoteEphPubKey = key2;
        if(applicationType == UA_APPLICATIONTYPE_SERVER)
            label = &clientLabel;
        else
            label = &serverLabel;
    } else if(pubKeyLen == key2->length &&
              memcmp(keyPubEnc, key2->data, key2->length) == 0) {
        /* Key 2 is local ephemeral public key => generating local keys */
        remoteEphPubKey = &key1Effective;
        if(applicationType == UA_APPLICATIONTYPE_SERVER)
            label = &serverLabel;
        else
            label = &clientLabel;
    } else {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* XDHE key agreement */
    ret = UA_OpenSSL_XDHE(keyType, localEphemeralKeyPair, remoteEphPubKey, &sharedSecret);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    /* IKM chaining */
    if(ikmPrependLength > 0) {
        if(ikmPrev.length != sharedSecret.length) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        UA_StatusCode alloc = UA_ByteString_allocBuffer(&ikm, sharedSecret.length);
        if(alloc != UA_STATUSCODE_GOOD) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        for(size_t i = 0; i < sharedSecret.length; i++)
            ikm.data[i] = (UA_Byte)(ikmPrev.data[i] ^ sharedSecret.data[i]);
        memcpy(ikmPrev.data, ikm.data, ikm.length);
        secret = &ikm;
    } else {
        secret = &sharedSecret;
    }

    /* Generate salt */
    ret = UA_OpenSSL_ECC_GenerateSalt(out->length, label, key2, &key1Effective, &salt);
    if(ret != UA_STATUSCODE_GOOD)
        goto errout;

    /* HKDF to derive keys */
    ret = UA_OpenSSL_HKDF((char*)(uintptr_t)hashAlgorithm, secret, &salt, &salt, out);

errout:
    UA_ByteString_clear(&sharedSecret);
    UA_ByteString_clear(&salt);
    UA_ByteString_clear(&ikm);
    return ret;
}

/* ChaCha20-Poly1305 AEAD Encrypt */

UA_StatusCode
UA_OpenSSL_ChaCha20Poly1305_Encrypt(const UA_ByteString *iv,
                                    const UA_ByteString *key,
                                    const UA_ByteString *aad,
                                    UA_ByteString *data,
                                    UA_Boolean encryptData) {
    if(iv->length != 12 || key->length != 32)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The last 16 bytes of data are reserved for the Poly1305 tag */
    if(data->length < 16)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainLen = data->length - 16;
    UA_Byte *tagPos = data->data + plainLen;

    if(!encryptData) {
        /* Sign-only mode: use ChaCha20-Poly1305 AEAD to compute the
         * Poly1305 tag. Treat all data (AAD + plaintext) as AAD so
         * nothing is encrypted, but the AEAD derives a proper one-time
         * Poly1305 key from the ChaCha20 keystream with the nonce. */
        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
        if(!ctx)
            return UA_STATUSCODE_BADOUTOFMEMORY;

        UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
        if(EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(),
                              NULL, NULL, NULL) != 1)
            goto so_errout;
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
            goto so_errout;
        if(EVP_EncryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
            goto so_errout;

        int outl = 0;
        /* Include AAD header */
        if(aad && aad->length > 0) {
            if(EVP_EncryptUpdate(ctx, NULL, &outl,
                                 aad->data, (int)aad->length) != 1)
                goto so_errout;
        }
        /* Include plaintext as additional AAD (not encrypted) */
        if(plainLen > 0) {
            if(EVP_EncryptUpdate(ctx, NULL, &outl,
                                 data->data, (int)plainLen) != 1)
                goto so_errout;
        }

        UA_Byte dummy;
        if(EVP_EncryptFinal_ex(ctx, &dummy, &outl) != 1)
            goto so_errout;
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagPos) != 1)
            goto so_errout;

        ret = UA_STATUSCODE_GOOD;
    so_errout:
        EVP_CIPHER_CTX_free(ctx);
        return ret;
    }

    /* SignAndEncrypt mode: full ChaCha20-Poly1305 AEAD */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto errout;

    /* Set IV length to 12 */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;

    if(EVP_EncryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
        goto errout;

    /* Process AAD */
    int outl = 0;
    if(aad && aad->length > 0) {
        if(EVP_EncryptUpdate(ctx, NULL, &outl, aad->data, (int)aad->length) != 1)
            goto errout;
    }

    /* Encrypt the plaintext in-place */
    if(EVP_EncryptUpdate(ctx, data->data, &outl, data->data, (int)plainLen) != 1)
        goto errout;

    int tmpLen = 0;
    if(EVP_EncryptFinal_ex(ctx, data->data + outl, &tmpLen) != 1)
        goto errout;

    /* Get the 16-byte authentication tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagPos) != 1)
        goto errout;

    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

/* ChaCha20-Poly1305 AEAD Decrypt */

UA_StatusCode
UA_OpenSSL_ChaCha20Poly1305_Decrypt(const UA_ByteString *iv,
                                    const UA_ByteString *key,
                                    const UA_ByteString *aad,
                                    UA_ByteString *data,
                                    UA_Boolean decryptData) {
    if(iv->length != 12 || key->length != 32)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The last 16 bytes are the Poly1305 tag */
    if(data->length < 16)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t cipherLen = data->length - 16;
    UA_Byte *tagPos = data->data + cipherLen;

    if(!decryptData) {
        /* Verify-only mode: use ChaCha20-Poly1305 AEAD to verify the
         * Poly1305 tag. All data is treated as AAD (not decrypted). */
        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
        if(!ctx)
            return UA_STATUSCODE_BADOUTOFMEMORY;

        UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
        if(EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(),
                              NULL, NULL, NULL) != 1)
            goto vo_errout;
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
            goto vo_errout;
        if(EVP_DecryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
            goto vo_errout;

        /* Set the expected tag for verification */
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, tagPos) != 1)
            goto vo_errout;

        int outl = 0;
        /* Include AAD header */
        if(aad && aad->length > 0) {
            if(EVP_DecryptUpdate(ctx, NULL, &outl,
                                 aad->data, (int)aad->length) != 1)
                goto vo_errout;
        }
        /* Include data as additional AAD (not decrypted) */
        if(cipherLen > 0) {
            if(EVP_DecryptUpdate(ctx, NULL, &outl,
                                 data->data, (int)cipherLen) != 1)
                goto vo_errout;
        }

        /* Finalize triggers tag verification */
        UA_Byte dummy;
        if(EVP_DecryptFinal_ex(ctx, &dummy, &outl) != 1) {
            ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            goto vo_errout;
        }

        /* Strip the tag from the output */
        data->length = cipherLen;
        ret = UA_STATUSCODE_GOOD;
    vo_errout:
        EVP_CIPHER_CTX_free(ctx);
        return ret;
    }

    /* SignAndEncrypt mode: full ChaCha20-Poly1305 AEAD decrypt */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto d_errout;

    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto d_errout;

    if(EVP_DecryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
        goto d_errout;

    /* Set the expected tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, tagPos) != 1)
        goto d_errout;

    /* Process AAD */
    int outl = 0;
    if(aad && aad->length > 0) {
        if(EVP_DecryptUpdate(ctx, NULL, &outl, aad->data, (int)aad->length) != 1)
            goto d_errout;
    }

    /* Decrypt in-place */
    if(EVP_DecryptUpdate(ctx, data->data, &outl, data->data, (int)cipherLen) != 1)
        goto d_errout;

    int tmpLen = 0;
    if(EVP_DecryptFinal_ex(ctx, data->data + outl, &tmpLen) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto d_errout;
    }

    /* Strip the tag from the output length */
    data->length = cipherLen;
    ret = UA_STATUSCODE_GOOD;
d_errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

/* AES-128-GCM AEAD Encrypt */

UA_StatusCode
UA_OpenSSL_AES_128_GCM_Encrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               const UA_ByteString *aad,
                               UA_ByteString *data,
                               UA_Boolean encryptData) {
    if(iv->length != 12 || key->length != 16)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The last 16 bytes of data are reserved for the GCM tag */
    if(data->length < 16)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainLen = data->length - 16;
    UA_Byte *tagPos = data->data + plainLen;

    if(!encryptData) {
        /* Sign-only mode: use AES-128-GCM AEAD to compute the GCM tag.
         * Treat all data (AAD + plaintext) as AAD so nothing is encrypted,
         * but the AEAD still produces a proper authentication tag. */
        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
        if(!ctx)
            return UA_STATUSCODE_BADOUTOFMEMORY;

        UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
        if(EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(),
                              NULL, NULL, NULL) != 1)
            goto so_errout;
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
            goto so_errout;
        if(EVP_EncryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
            goto so_errout;

        int outl = 0;
        /* Include AAD header */
        if(aad && aad->length > 0) {
            if(EVP_EncryptUpdate(ctx, NULL, &outl,
                                 aad->data, (int)aad->length) != 1)
                goto so_errout;
        }
        /* Include plaintext as additional AAD (not encrypted) */
        if(plainLen > 0) {
            if(EVP_EncryptUpdate(ctx, NULL, &outl,
                                 data->data, (int)plainLen) != 1)
                goto so_errout;
        }

        UA_Byte dummy;
        if(EVP_EncryptFinal_ex(ctx, &dummy, &outl) != 1)
            goto so_errout;
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagPos) != 1)
            goto so_errout;

        ret = UA_STATUSCODE_GOOD;
    so_errout:
        EVP_CIPHER_CTX_free(ctx);
        return ret;
    }

    /* SignAndEncrypt mode: full AES-128-GCM AEAD */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1)
        goto errout;

    /* Set IV length to 12 (the GCM spec default; explicit for clarity) */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;

    if(EVP_EncryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
        goto errout;

    /* Process AAD */
    int outl = 0;
    if(aad && aad->length > 0) {
        if(EVP_EncryptUpdate(ctx, NULL, &outl, aad->data, (int)aad->length) != 1)
            goto errout;
    }

    /* Encrypt the plaintext in-place */
    if(EVP_EncryptUpdate(ctx, data->data, &outl, data->data, (int)plainLen) != 1)
        goto errout;

    int tmpLen = 0;
    if(EVP_EncryptFinal_ex(ctx, data->data + outl, &tmpLen) != 1)
        goto errout;

    /* Get the 16-byte authentication tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagPos) != 1)
        goto errout;

    ret = UA_STATUSCODE_GOOD;
errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

/* AES-128-GCM AEAD Decrypt */

UA_StatusCode
UA_OpenSSL_AES_128_GCM_Decrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               const UA_ByteString *aad,
                               UA_ByteString *data,
                               UA_Boolean decryptData) {
    if(iv->length != 12 || key->length != 16)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The last 16 bytes are the GCM tag */
    if(data->length < 16)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t cipherLen = data->length - 16;
    UA_Byte *tagPos = data->data + cipherLen;

    if(!decryptData) {
        /* Verify-only mode: use AES-128-GCM AEAD to verify the GCM tag.
         * All data is treated as AAD (not decrypted). */
        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
        if(!ctx)
            return UA_STATUSCODE_BADOUTOFMEMORY;

        UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
        if(EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(),
                              NULL, NULL, NULL) != 1)
            goto vo_errout;
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
            goto vo_errout;
        if(EVP_DecryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
            goto vo_errout;

        /* Set the expected tag for verification */
        if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, tagPos) != 1)
            goto vo_errout;

        int outl = 0;
        /* Include AAD header */
        if(aad && aad->length > 0) {
            if(EVP_DecryptUpdate(ctx, NULL, &outl,
                                 aad->data, (int)aad->length) != 1)
                goto vo_errout;
        }
        /* Include data as additional AAD (not decrypted) */
        if(cipherLen > 0) {
            if(EVP_DecryptUpdate(ctx, NULL, &outl,
                                 data->data, (int)cipherLen) != 1)
                goto vo_errout;
        }

        /* Finalize triggers tag verification */
        UA_Byte dummy;
        if(EVP_DecryptFinal_ex(ctx, &dummy, &outl) != 1) {
            ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            goto vo_errout;
        }

        /* Strip the tag from the output */
        data->length = cipherLen;
        ret = UA_STATUSCODE_GOOD;
    vo_errout:
        EVP_CIPHER_CTX_free(ctx);
        return ret;
    }

    /* SignAndEncrypt mode: full AES-128-GCM AEAD decrypt */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1)
        goto d_errout;

    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto d_errout;

    if(EVP_DecryptInit_ex(ctx, NULL, NULL, key->data, iv->data) != 1)
        goto d_errout;

    /* Set the expected tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, tagPos) != 1)
        goto d_errout;

    /* Process AAD */
    int outl = 0;
    if(aad && aad->length > 0) {
        if(EVP_DecryptUpdate(ctx, NULL, &outl, aad->data, (int)aad->length) != 1)
            goto d_errout;
    }

    /* Decrypt in-place */
    if(EVP_DecryptUpdate(ctx, data->data, &outl, data->data, (int)cipherLen) != 1)
        goto d_errout;

    int tmpLen = 0;
    if(EVP_DecryptFinal_ex(ctx, data->data + outl, &tmpLen) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto d_errout;
    }

    /* Strip the tag from the output length */
    data->length = cipherLen;
    ret = UA_STATUSCODE_GOOD;
d_errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}


#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_basic128rsa15.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/evp.h>

#define UA_SHA1_LENGTH                                               20
#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN               11
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH    16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE    16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH       16
#define UA_SHA1_LENGTH                                               20

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
} Policy_Context_Basic128Rsa15;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509;
} Channel_Context_Basic128Rsa15;

static UA_StatusCode
UA_Policy_Basic128Rsa15_New_Context(UA_SecurityPolicy * securityPolicy,
                                    const UA_ByteString localPrivateKey,
                                    const UA_Logger *   logger) {
    Policy_Context_Basic128Rsa15 * context = (Policy_Context_Basic128Rsa15 *)
                                    UA_malloc(sizeof(Policy_Context_Basic128Rsa15));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval =
        UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                 &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    securityPolicy->policyContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_Basic128Rsa15_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;
    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_Basic128Rsa15 *ctx = (Policy_Context_Basic128Rsa15 *)
        policy->policyContext;
    if(ctx == NULL)
        return;

    /* delete all allocated members in the context */

    EVP_PKEY_free(ctx->localPrivateKey);
    EVP_PKEY_free(ctx->csrLocalPrivateKey);
    UA_ByteString_clear(&ctx->localCertThumbprint);
    UA_free(ctx);
}

static UA_StatusCode
updateCertificate_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                   const UA_ByteString newCertificate,
                                   const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic128Rsa15 *pc =
        (Policy_Context_Basic128Rsa15 *)securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate, EVP_PKEY_RSA);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        EVP_PKEY_free(pc->localPrivateKey);
        pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    } else {
        if(!isLocalKey) {
            EVP_PKEY_free(pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            pc->csrLocalPrivateKey = NULL;
        }
    }

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADNOTSUPPORTED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Basic128Rsa15_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                      const UA_String *subjectName,
                                      const UA_ByteString *nonce,
                                      const UA_KeyValueMap *params,
                                      UA_ByteString *csr,
                                      UA_ByteString *newPrivateKey) {
    /* Check parameter */
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic128Rsa15 *pc =
            (Policy_Context_Basic128Rsa15 *) securityPolicy->policyContext;

    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName, nonce,
                                           csr, newPrivateKey);
}

/* create the channel context */

static UA_StatusCode
Basic128Rsa15_New_Context(const UA_SecurityPolicy *securityPolicy,
                          const UA_ByteString *remoteCertificate,
                          void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic128Rsa15 * context = (Channel_Context_Basic128Rsa15 *)
            UA_malloc(sizeof(Channel_Context_Basic128Rsa15));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval = UA_copyCertificate(&context->remoteCertificate,
                                              remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&context->remoteCertificate, EVP_PKEY_RSA);
    if(context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear(&context->remoteCertificate);
        UA_free(context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
Basic128Rsa15_Delete_Context(const UA_SecurityPolicy *policy,
                             void *channelContext) {
    if(channelContext == NULL)
        return;

    Channel_Context_Basic128Rsa15 *cc =
        (Channel_Context_Basic128Rsa15 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_free(cc);
}

static UA_StatusCode
Basic128Rsa15_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                    void *channelContext,
                                    const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
Basic128Rsa15_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                       void *channelContext,
                                       const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
Basic128Rsa15_setLocalSymIv(const UA_SecurityPolicy *policy,
                            void *channelContext,
                            const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
Basic128Rsa15_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
Basic128Rsa15_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                        void *channelContext,
                                        const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
Basic128Rsa15_setRemoteSymIv(const UA_SecurityPolicy *policy,
                             void *channelContext,
                             const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
Basic128Rsa15_compareCertificate(const UA_SecurityPolicy *policy,
                                 const void *channelContext,
                                 const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic128Rsa15 * cc =
        (const Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static UA_StatusCode
UA_Asy_Basic128Rsa15_compareCertThumbprint(const UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Basic128Rsa15 *pc = (Policy_Context_Basic128Rsa15 *)
                                       securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) {
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Asy_Basic128Rsa15_makeCertificateThumbprint(const UA_SecurityPolicy *securityPolicy,
                                               const UA_ByteString *certificate,
                                               UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static size_t
UA_AsySig_Basic128Rsa15_getRemoteSignatureSize (const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic128Rsa15 *cc =
        (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsySig_Basic128Rsa15_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Basic128Rsa15 *pc =
        (Policy_Context_Basic128Rsa15 *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t) keyLen;
}

static UA_StatusCode
UA_AsySig_Basic128Rsa15_Verify(const UA_SecurityPolicy *policy, void *channelContext,
                               const UA_ByteString *message,
                               const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(message, cc->remoteCertificateX509,
                                                signature);
}

static UA_StatusCode
UA_AsySig_Basic128Rsa15_Sign(const UA_SecurityPolicy *policy, void *channelContext,
                             const UA_ByteString *message, UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Policy_Context_Basic128Rsa15 *pc =
        (const Policy_Context_Basic128Rsa15*) policy->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(message, pc->localPrivateKey, signature);
}

static size_t
UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic128Rsa15 *cc =
        (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_StatusCode retval =
        UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    if(retval != UA_STATUSCODE_GOOD ||
       keyLen <= (UA_Int32)UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN)
        return 0;
    return (size_t) keyLen - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Basic128Rsa15_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic128Rsa15 *cc =
        (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic128Rsa15_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic128Rsa15 *cc =
        (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen * 8;
}

static size_t
UA_AsymEn_Basic128Rsa15_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Policy_Context_Basic128Rsa15 *pc =
        (const Policy_Context_Basic128Rsa15 *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t) keyLen * 8;
}

static UA_StatusCode
UA_AsymEn_Basic128Rsa15_Decrypt(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Policy_Context_Basic128Rsa15 *pc =
        (const Policy_Context_Basic128Rsa15 *)policy->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_Decrypt(data, pc->localPrivateKey);
}

static UA_StatusCode
UA_AsymEn_Basic128Rsa15_Encrypt(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if (channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_Openssl_RSA_PKCS1_V15_Encrypt(data,
                                            UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN,
                                            cc->remoteCertificateX509);
}

static UA_StatusCode
UA_Sym_Basic128Rsa15_generateNonce(const UA_SecurityPolicy *policy,
                                   void *channelContext, UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int) out->length);
    if(rc != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Sym_Basic128Rsa15_generateKey(const UA_SecurityPolicy *policy,
                                 void *channelContext, const UA_ByteString *secret,
                                 const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA1_Derive(secret, seed, out);
}

static size_t
UA_SymEn_Basic128Rsa15_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Basic128Rsa15_getBlockSize(const UA_SecurityPolicy *policy,
                                    const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymEn_Basic128Rsa15_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH;
}

static UA_StatusCode
UA_SymEn_Basic128Rsa15_Encrypt(const UA_SecurityPolicy *policy,
                               void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_AES_128_CBC_Encrypt(&cc->localSymIv,
                                          &cc->localSymEncryptingKey, data);
}

static UA_StatusCode
UA_SymEn_Basic128Rsa15_Decrypt(const UA_SecurityPolicy *policy,
                               void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15*)channelContext;
    return UA_OpenSSL_AES_128_CBC_Decrypt(&cc->remoteSymIv,
                                          &cc->remoteSymEncryptingKey, data);
}

static size_t
UA_SymSig_Basic128Rsa15_getKeyLength(const UA_SecurityPolicy *policy,
                                     const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH;
}

static size_t
UA_SymSig_Basic128Rsa15_getSignatureSize(const UA_SecurityPolicy *policy,
                                    const void *channelContext) {
    return UA_SHA1_LENGTH;
}

static UA_StatusCode
UA_SymSig_Basic128Rsa15_Verify(const UA_SecurityPolicy *policy, void *channelContext,
                               const UA_ByteString *message,
                               const UA_ByteString *signature) {
    if (channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_Basic128Rsa15_Sign(const UA_SecurityPolicy *policy,
                          void *channelContext, const UA_ByteString *message,
                          UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Sign(message, &cc->localSymSigningKey, signature);
}

UA_StatusCode
UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *sp,
                                const UA_ByteString localCertificate,
                                const UA_ByteString localPrivateKey,
                                const UA_Logger *logger) {
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "!! WARNING !! The Basic128Rsa15 SecurityPolicy is unsecure. "
                   "There are known attacks that break the encryption.");

    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15\0");
    sp->certificateGroupId = UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSAMINAPPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 0;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
    asymSig->verify = UA_AsySig_Basic128Rsa15_Verify;
    asymSig->sign = UA_AsySig_Basic128Rsa15_Sign;
    asymSig->getLocalSignatureSize = UA_AsySig_Basic128Rsa15_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_AsySig_Basic128Rsa15_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5\0");
    asymEnc->encrypt = UA_AsymEn_Basic128Rsa15_Encrypt;
    asymEnc->decrypt = UA_AsymEn_Basic128Rsa15_Decrypt;
    asymEnc->getLocalKeyLength = UA_AsymEn_Basic128Rsa15_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_Basic128Rsa15_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_Basic128Rsa15_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize;

    /* Symmetric signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    symSig->verify = UA_SymSig_Basic128Rsa15_Verify;
    symSig->sign = UA_SymSig_Basic128Rsa15_Sign;
    symSig->getLocalSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEnc->encrypt = UA_SymEn_Basic128Rsa15_Encrypt;
    symEnc->decrypt = UA_SymEn_Basic128Rsa15_Decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_Basic128Rsa15_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_Basic128Rsa15_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = Basic128Rsa15_New_Context;
    sp->deleteChannelContext = Basic128Rsa15_Delete_Context;
    sp->setLocalSymEncryptingKey = Basic128Rsa15_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = Basic128Rsa15_setLocalSymSigningKey;
    sp->setLocalSymIv = Basic128Rsa15_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = Basic128Rsa15_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = Basic128Rsa15_setRemoteSymSigningKey;
    sp->setRemoteSymIv = Basic128Rsa15_setRemoteSymIv;
    sp->compareCertificate = Basic128Rsa15_compareCertificate;
    sp->generateKey = UA_Sym_Basic128Rsa15_generateKey;
    sp->generateNonce = UA_Sym_Basic128Rsa15_generateNonce;
    sp->nonceLength = 16;  /* 128 bits*/
    sp->makeCertThumbprint = UA_Asy_Basic128Rsa15_makeCertificateThumbprint;
    sp->compareCertThumbprint = UA_Asy_Basic128Rsa15_compareCertThumbprint;
    sp->updateCertificate = updateCertificate_sp_basic128rsa15;
    sp->createSigningRequest = createSigningRequest_sp_basic128rsa15;
    sp->clear = UA_Policy_Basic128Rsa15_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_RSA);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_Basic128Rsa15_New_Context(sp, localPrivateKey, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_basic256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/x509.h>
#include <openssl/rand.h>

#define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN                42
#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH         32
#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE         16
#define UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH            24
#define UA_SHA1_LENGTH                                               20

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
} Policy_Context_Basic256;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509;
} Channel_Context_Basic256;

static UA_StatusCode
UA_Policy_Basic256_New_Context(UA_SecurityPolicy *securityPolicy,
                               const UA_ByteString localPrivateKey,
                               const UA_Logger *logger) {
    Policy_Context_Basic256 * context = (Policy_Context_Basic256 *)
        UA_malloc(sizeof (Policy_Context_Basic256));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free (context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval =
        UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                 &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free (context);
        return retval;
    }

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_Basic256_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);
    Policy_Context_Basic256 * ctx = (Policy_Context_Basic256 *) policy->policyContext;
    if(ctx == NULL)
        return;

    EVP_PKEY_free(ctx->localPrivateKey);
    EVP_PKEY_free(ctx->csrLocalPrivateKey);
    UA_ByteString_clear(&ctx->localCertThumbprint);
    UA_free (ctx);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString newCertificate,
                                           const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic256 *pc =
        (Policy_Context_Basic256 *)securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
                                                           &newCertificate, &securityPolicy->localCertificate, EVP_PKEY_RSA);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        EVP_PKEY_free(pc->localPrivateKey);
        pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    } else {
        if(!isLocalKey) {
            EVP_PKEY_free(pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            pc->csrLocalPrivateKey = NULL;
        }
    }

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADNOTSUPPORTED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Basic256_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                 const UA_String *subjectName,
                                 const UA_ByteString *nonce,
                                 const UA_KeyValueMap *params,
                                 UA_ByteString *csr,
                                 UA_ByteString *newPrivateKey) {
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic256 *pc =
            (Policy_Context_Basic256 *) securityPolicy->policyContext;

    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName, nonce,
                                           csr, newPrivateKey);
}

/* create the channel context */

static UA_StatusCode
Basic256_New_Context(const UA_SecurityPolicy * securityPolicy,
                                      const UA_ByteString *     remoteCertificate,
                                      void **                   channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Basic256 * context = (Channel_Context_Basic256 *)
        UA_malloc(sizeof(Channel_Context_Basic256));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval = UA_copyCertificate(&context->remoteCertificate,
                                              remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free (context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&context->remoteCertificate, EVP_PKEY_RSA);
    if(context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&context->remoteCertificate);
        UA_free (context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
Basic256_Delete_Context(const UA_SecurityPolicy *policy,
                        void *channelContext) {
    if(channelContext == NULL)
        return;
    Channel_Context_Basic256 *cc = (Channel_Context_Basic256 *) channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_free(cc);
}

static UA_StatusCode
UA_Asy_Basic256_compareCertificateThumbprint(const UA_SecurityPolicy *securityPolicy,
                                             const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Policy_Context_Basic256 *pc =
        (Policy_Context_Basic256 *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

/* Generates a thumbprint for the specified certificate */

static UA_StatusCode
UA_Asy_Basic256_makeCertificateThumbprint(const UA_SecurityPolicy * securityPolicy,
                                          const UA_ByteString *     certificate,
                                          UA_ByteString *           thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint (certificate, thumbprint, false);
}

static UA_StatusCode
Basic256_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
Basic256_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
Basic256_setLocalSymIv(const UA_SecurityPolicy *policy,
                       void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
Basic256_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
Basic256_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
Basic256_setRemoteSymIv(const UA_SecurityPolicy *policy,
                        void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
Basic256_compareCertificate(const UA_SecurityPolicy *policy,
                            const void *channelContext,
                            const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic256 *cc =
        (const Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsySig_Basic256_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic256 *cc =
        (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsySig_Basic256_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    if (channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Policy_Context_Basic256 *pc =
        (const Policy_Context_Basic256*)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen);
    return (size_t) keyLen;
}

static UA_StatusCode
UA_AsySig_Basic256_Verify(const UA_SecurityPolicy *policy, void *channelContext,
                          const UA_ByteString *message,
                          const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(message, cc->remoteCertificateX509,
                                                signature);
}

static UA_StatusCode
UA_AsySig_Basic256_Sign(const UA_SecurityPolicy *policy,
                        void *channelContext, const UA_ByteString *message,
                        UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Policy_Context_Basic256 *pc =
        (const Policy_Context_Basic256*)policy->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(message, pc->localPrivateKey, signature);
}

static size_t
UA_AsymEn_Basic256_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic256 *cc =
        (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_StatusCode retval =
        UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    if(retval != UA_STATUSCODE_GOOD ||
       keyLen <= (UA_Int32)UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN)
        return 0;
    return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Basic256_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                      const void *channelContext) {
    if (channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic256 *cc =
        (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                      const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Channel_Context_Basic256 *cc =
        (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen * 8;
}

static size_t
UA_AsymEn_Basic256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                     const void *channelContext) {
    if (channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Policy_Context_Basic256 *pc =
        (const Policy_Context_Basic256*)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t) keyLen * 8;
}

static UA_StatusCode
UA_AsymEn_Basic256_Decrypt(const UA_SecurityPolicy *policy,
                           void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    const Policy_Context_Basic256 *pc =
        (const Policy_Context_Basic256*)policy->policyContext;
    return UA_Openssl_RSA_Oaep_Decrypt(data, pc->localPrivateKey);
}

static UA_StatusCode
UA_AsymEn_Basic256_Encrypt(const UA_SecurityPolicy *policy,
                           void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_Openssl_RSA_OAEP_Encrypt(data, UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN,
                                       cc->remoteCertificateX509);
}

static UA_StatusCode
UA_Sym_Basic256_generateNonce(const UA_SecurityPolicy *policy,
                              void *channelContext, UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int) out->length);
    if(rc != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Sym_Basic256_generateKey(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *secret,
                            const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA1_Derive(secret, seed, out);
}

static size_t
UA_SymEn_Basic256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                    const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Basic256_getBlockSize(const UA_SecurityPolicy *policy,
                               const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymEn_Basic256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                     const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH;
}

static UA_StatusCode
UA_SymEn_Basic256_Encrypt(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv,
                                          &cc->localSymEncryptingKey, data);
}

static UA_StatusCode
UA_SymEn_Basic256_Decrypt(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv,
                                          &cc->remoteSymEncryptingKey, data);
}

static size_t
UA_SymSig_Basic256_getKeyLength(const UA_SecurityPolicy *policy,
                                const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH;
}

static size_t
UA_SymSig_Basic256_getSignatureSize (const UA_SecurityPolicy *policy,
                                     const void *channelContext) {
    return UA_SHA1_LENGTH;
}

static UA_StatusCode
UA_SymSig_Basic256_Verify(const UA_SecurityPolicy *policy, void *channelContext,
                          const UA_ByteString *message,
                          const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Verify (message, &cc->remoteSymSigningKey,
                                        signature);
}

static UA_StatusCode
UA_SymSig_Basic256_Sign(const UA_SecurityPolicy *policy,
                        void *channelContext, const UA_ByteString *message,
                        UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Sign(message, &cc->localSymSigningKey, signature);
}

UA_StatusCode
UA_SecurityPolicy_Basic256(UA_SecurityPolicy *sp,
                           const UA_ByteString localCertificate,
                           const UA_ByteString localPrivateKey,
                           const UA_Logger *logger) {
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "!! WARNING !! The Basic256 SecurityPolicy is unsecure. "
                   "There are known attacks that break the encryption.");

    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256\0");
    sp->certificateGroupId = UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSAMINAPPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 0;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
    asymSig->verify = UA_AsySig_Basic256_Verify;
    asymSig->sign = UA_AsySig_Basic256_Sign;
    asymSig->getLocalSignatureSize = UA_AsySig_Basic256_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_AsySig_Basic256_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asymEnc->encrypt = UA_AsymEn_Basic256_Encrypt;
    asymEnc->decrypt = UA_AsymEn_Basic256_Decrypt;
    asymEnc->getLocalKeyLength = UA_AsymEn_Basic256_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_Basic256_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_Basic256_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_Basic256_getRemotePlainTextBlockSize;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    symSig->verify = UA_SymSig_Basic256_Verify;
    symSig->sign = UA_SymSig_Basic256_Sign;
    symSig->getLocalSignatureSize = UA_SymSig_Basic256_getSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_Basic256_getSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_Basic256_getKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_Basic256_getKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = UA_SymEn_Basic256_Encrypt;
    symEnc->decrypt = UA_SymEn_Basic256_Decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_Basic256_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_Basic256_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_Basic256_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_Basic256_getBlockSize;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = Basic256_New_Context;
    sp->deleteChannelContext = Basic256_Delete_Context;
    sp->setLocalSymEncryptingKey = Basic256_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = Basic256_setLocalSymSigningKey;
    sp->setLocalSymIv = Basic256_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = Basic256_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = Basic256_setRemoteSymSigningKey;
    sp->setRemoteSymIv = Basic256_setRemoteSymIv;
    sp->compareCertificate = Basic256_compareCertificate;
    sp->generateKey = UA_Sym_Basic256_generateKey;
    sp->generateNonce = UA_Sym_Basic256_generateNonce;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = UA_Asy_Basic256_makeCertificateThumbprint;
    sp->compareCertThumbprint = UA_Asy_Basic256_compareCertificateThumbprint;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_basic256;
    sp->createSigningRequest = createSigningRequest_sp_basic256;
    sp->clear = UA_Policy_Basic256_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate, EVP_PKEY_RSA);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_Basic256_New_Context(sp, localPrivateKey, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_basic256sha256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>

#define UA_SHA256_LENGTH 32    /* 256 bit */
#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH 512

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
} Policy_Context_Basic256Sha256;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_Basic256Sha256;

static UA_StatusCode
UA_Policy_New_Context(UA_SecurityPolicy *securityPolicy,
                       const UA_ByteString localPrivateKey,
                       const UA_Logger *logger) {
    Policy_Context_Basic256Sha256 *context = (Policy_Context_Basic256Sha256 *)
        UA_malloc(sizeof(Policy_Context_Basic256Sha256));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval =
        UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                 &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *) policy->policyContext;
    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
    return;
}

static UA_StatusCode
updateCertificate_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                    const UA_ByteString newCertificate,
                                    const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *)securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
                                                           &newCertificate, &securityPolicy->localCertificate, EVP_PKEY_RSA);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        EVP_PKEY_free(pc->localPrivateKey);
        pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    } else {
        if(!isLocalKey) {
            EVP_PKEY_free(pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            pc->csrLocalPrivateKey = NULL;
        }
    }

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADNOTSUPPORTED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                       const UA_String *subjectName,
                                       const UA_ByteString *nonce,
                                       const UA_KeyValueMap *params,
                                       UA_ByteString *csr,
                                       UA_ByteString *newPrivateKey) {
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Basic256Sha256 *pc =
            (Policy_Context_Basic256Sha256 *) securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName, nonce,
                                           csr, newPrivateKey);
}

static UA_StatusCode
New_Context(const UA_SecurityPolicy * securityPolicy,
            const UA_ByteString * remoteCertificate,
            void ** channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Basic256Sha256 *context = (Channel_Context_Basic256Sha256 *)
        UA_malloc(sizeof(Channel_Context_Basic256Sha256));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval =
        UA_copyCertificate(&context->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&context->remoteCertificate, EVP_PKEY_RSA);
    if(context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear(&context->remoteCertificate);
        UA_free(context);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    *channelContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
Delete_Context(const UA_SecurityPolicy *policy,
               void *channelContext) {
    if(!channelContext)
        return;

    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_free(cc);
}

static UA_StatusCode
UA_AsySig_Basic256Sha256_Verify(const UA_SecurityPolicy *policy, void *channelContext,
                                const UA_ByteString *message,
                                const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(message, cc->remoteCertificateX509,
                                                  signature);
}

static UA_StatusCode
UA_compareCertificateThumbprint(const UA_SecurityPolicy *policy,
                                const UA_ByteString *thumbprint) {
    if(policy == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *)policy->policyContext;
    if(!UA_ByteString_equal(thumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint(const UA_SecurityPolicy *policy,
                             const UA_ByteString *certificate,
                             UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_Asym_Basic256Sha256_Decrypt(const UA_SecurityPolicy *policy,
                               void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *)policy->policyContext;
    return UA_Openssl_RSA_Oaep_Decrypt(data, pc->localPrivateKey);
}

static size_t
UA_Asym_Basic256Sha256_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Basic256Sha256 * cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsySig_Basic256Sha256_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Basic256Sha256 *cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_StatusCode retval =
        UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    if(retval != UA_STATUSCODE_GOOD ||
       keyLen <= (UA_Int32)UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN)
        return 0;
    return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Basic256Sha256_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Basic256Sha256 * cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic256Sha256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Basic256Sha256 *cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen * 8;
}

static UA_StatusCode
UA_Sym_Basic256Sha256_generateNonce(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int) out->length);
    if(rc != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymEn_Basic256Sha256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_Basic256Sha256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_Basic256Sha256_generateKey(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *secret,
                                  const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out);
}

static UA_StatusCode
Basic256Sha256_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
Basic256Sha256_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                        void *channelContext,
                                        const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
Basic256Sha256_setLocalSymIv(const UA_SecurityPolicy *policy,
                             void *channelContext,
                             const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_Basic256Sha256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Basic256Sha256_getBlockSize(const UA_SecurityPolicy *policy,
                                     const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_Basic256Sha256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
Basic256Sha256_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
Basic256Sha256_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
Basic256Sha256_setRemoteSymIv(const UA_SecurityPolicy *policy,
                              void *channelContext,
                              const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsySig_Basic256Sha256_sign(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *message,
                              UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *)policy->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymEn_Basic256Sha256_encrypt(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_Openssl_RSA_OAEP_Encrypt(data,
                                       UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN,
                                       cc->remoteCertificateX509);
}

static size_t
UA_SymSig_Basic256Sha256_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_Basic256Sha256_verify(const UA_SecurityPolicy *policy, void *channelContext,
                                const UA_ByteString *message,
                                const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc = (Channel_Context_Basic256Sha256*)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_Basic256Sha256_sign(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *message,
                              UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc = (Channel_Context_Basic256Sha256*)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_Basic256Sha256_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_Basic256Sha256_decrypt(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc = (Channel_Context_Basic256Sha256*)channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv,
                                          &cc->remoteSymEncryptingKey, data);
}

static UA_StatusCode
UA_SymEn_Basic256Sha256_encrypt(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv,
                                          &cc->localSymEncryptingKey, data);
}

static UA_StatusCode
Basic256Sha256_compareCertificate(const UA_SecurityPolicy *policy,
                                  const void *channelContext,
                                  const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Basic256Sha256 * cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_Basic256Sha256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t) keyLen * 8;
}

UA_StatusCode
UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *sp,
                                 const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey,
                                 const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256\0");
    sp->certificateGroupId = UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSASHA256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 20;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    asymSig->verify = UA_AsySig_Basic256Sha256_Verify;
    asymSig->sign = UA_AsySig_Basic256Sha256_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_Basic256Sha256_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_Basic256Sha256_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asymEnc->encrypt = UA_AsymEn_Basic256Sha256_encrypt;
    asymEnc->decrypt = UA_Asym_Basic256Sha256_Decrypt;
    asymEnc->getLocalKeyLength = UA_AsymEn_Basic256Sha256_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_Basic256Sha256_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_Basic256Sha256_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSig->verify = UA_SymSig_Basic256Sha256_verify;
    symSig->sign = UA_SymSig_Basic256Sha256_sign;
    symSig->getLocalSignatureSize = UA_SymSig_Basic256Sha256_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_Basic256Sha256_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_Basic256Sha256_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_Basic256Sha256_getRemoteKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = UA_SymEn_Basic256Sha256_encrypt;
    symEnc->decrypt = UA_SymEn_Basic256Sha256_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_Basic256Sha256_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_Basic256Sha256_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_Basic256Sha256_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_Basic256Sha256_getBlockSize;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = New_Context;
    sp->deleteChannelContext = Delete_Context;
    sp->setLocalSymEncryptingKey = Basic256Sha256_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = Basic256Sha256_setLocalSymSigningKey;
    sp->setLocalSymIv = Basic256Sha256_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = Basic256Sha256_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = Basic256Sha256_setRemoteSymSigningKey;
    sp->setRemoteSymIv = Basic256Sha256_setRemoteSymIv;
    sp->compareCertificate = Basic256Sha256_compareCertificate;
    sp->generateKey = UA_Sym_Basic256Sha256_generateKey;
    sp->generateNonce = UA_Sym_Basic256Sha256_generateNonce;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint;
    sp->updateCertificate = updateCertificate_sp_basic256sha256;
    sp->createSigningRequest = createSigningRequest_sp_basic256sha256;
    sp->clear = UA_Policy_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate, EVP_PKEY_RSA);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_New_Context(sp, localPrivateKey, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_aes128sha256rsaoaep.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN 42
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH 512

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
} Policy_Context_Aes128Sha256RsaOaep;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_Aes128Sha256RsaOaep;

static UA_StatusCode
UA_Policy_Aes128Sha256RsaOaep_New_Context(UA_SecurityPolicy *securityPolicy,
                                          const UA_ByteString localPrivateKey,
                                          const UA_Logger *logger) {
    Policy_Context_Aes128Sha256RsaOaep *context = (Policy_Context_Aes128Sha256RsaOaep *)
        UA_malloc(sizeof(Policy_Context_Aes128Sha256RsaOaep));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    securityPolicy->policyContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_Aes128Sha256RsaOaep_Clear_Context(UA_SecurityPolicy *policy) {
    if(policy == NULL || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)policy->policyContext;
    if(pc == NULL)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                                      const UA_ByteString newCertificate,
                                                      const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate, &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
                                                           &newCertificate, &securityPolicy->localCertificate, EVP_PKEY_RSA);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        EVP_PKEY_free(pc->localPrivateKey);
        pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    } else {
        if(!isLocalKey) {
            EVP_PKEY_free(pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            pc->csrLocalPrivateKey = NULL;
        }
    }

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADNOTSUPPORTED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Aes128Sha256RsaOaep_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
createSigningRequest_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                            const UA_String *subjectName,
                                            const UA_ByteString *nonce,
                                            const UA_KeyValueMap *params,
                                            UA_ByteString *csr,
                                            UA_ByteString *newPrivateKey) {
    if(securityPolicy == NULL || csr == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes128Sha256RsaOaep *pc =
            (Policy_Context_Aes128Sha256RsaOaep *) securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName, nonce,
                                           csr, newPrivateKey);
}

static UA_StatusCode
Aes128Sha256RsaOaep_New_Context(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *remoteCertificate,
                                                 void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes128Sha256RsaOaep *context =
        (Channel_Context_Aes128Sha256RsaOaep *)
        UA_malloc(sizeof(Channel_Context_Aes128Sha256RsaOaep));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval =
        UA_copyCertificate(&context->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&context->remoteCertificate, EVP_PKEY_RSA);
    if(context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&context->remoteCertificate);
        UA_free (context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
Aes128Sha256RsaOaep_Delete_Context(const UA_SecurityPolicy *policy,
                                                    void *channelContext) {
    if(channelContext == NULL)
        return;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_free(cc);
}

static UA_StatusCode
UA_AsySig_Aes128Sha256RsaOaep_Verify(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(message, cc->remoteCertificateX509,
                                                  signature);
}

static UA_StatusCode
UA_compareCertificateThumbprint_Aes128Sha256RsaOaep(const UA_SecurityPolicy *sp,
                                                    const UA_ByteString *certificateThumbprint) {
    if(sp == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)sp->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_Aes128Sha256RsaOaep(const UA_SecurityPolicy *sp,
                                                 const UA_ByteString *certificate,
                                                 UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_Asym_Aes128Sha256RsaOaep_Decrypt(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)policy->policyContext;
    return UA_Openssl_RSA_Oaep_Decrypt(data, pc->localPrivateKey);
}

static size_t
UA_Asym_Aes128Sha256RsaOaep_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsySig_Aes128Sha256RsaOaep_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                          const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_StatusCode retval =
        UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    if(retval != UA_STATUSCODE_GOOD ||
       keyLen <= (UA_Int32)UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN)
        return 0;
    return (size_t)keyLen - UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen * 8;
}

static UA_StatusCode
UA_Sym_Aes128Sha256RsaOaep_generateNonce(const UA_SecurityPolicy *policy,
                                         void *channelContext, UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    if(rc != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymEn_Aes128Sha256RsaOaep_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_Aes128Sha256RsaOaep_generateKey(const UA_SecurityPolicy *policy,
                                       void *channelContext, const UA_ByteString *secret,
                                       const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out);
}

static UA_StatusCode
Aes128Sha256RsaOaep_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                                         void *channelContext,
                                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymIv(const UA_SecurityPolicy *policy,
                                              void *channelContext,
                                              const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_Aes128Sha256RsaOaep_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Aes128Sha256RsaOaep_getBlockSize(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                                       void *channelContext,
                                                       const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                                          void *channelContext,
                                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymIv(const UA_SecurityPolicy *policy,
                                               void *channelContext,
                                               const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsySig_Aes128Sha256RsaOaep_sign(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)policy->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymEn_Aes128Sha256RsaOaep_encrypt(const UA_SecurityPolicy *policy,
                                      void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_Openssl_RSA_OAEP_Encrypt(
        data, UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN,
        cc->remoteCertificateX509);
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_Aes128Sha256RsaOaep_verify(const UA_SecurityPolicy *policy, void *channelContext,
                                     const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_Aes128Sha256RsaOaep_sign(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_Aes128Sha256RsaOaep_decrypt(const UA_SecurityPolicy *policy,
                                     void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_Aes128Sha256RsaOaep_encrypt(const UA_SecurityPolicy *policy,
                                     void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_compareCertificate(const UA_SecurityPolicy *policy,
                                                   const void *channelContext,
                                                   const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen * 8;
}

UA_StatusCode
UA_SecurityPolicy_Aes128Sha256RsaOaep(UA_SecurityPolicy *sp,
                                      const UA_ByteString localCertificate,
                                      const UA_ByteString localPrivateKey,
                                      const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep\0");
    sp->certificateGroupId = UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSASHA256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    asymSig->verify = UA_AsySig_Aes128Sha256RsaOaep_Verify;
    asymSig->sign = UA_AsySig_Aes128Sha256RsaOaep_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_Aes128Sha256RsaOaep_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_Aes128Sha256RsaOaep_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asymEnc->encrypt = UA_AsymEn_Aes128Sha256RsaOaep_encrypt;
    asymEnc->decrypt = UA_Asym_Aes128Sha256RsaOaep_Decrypt;
    asymEnc->getLocalKeyLength = UA_AsymEn_Aes128Sha256RsaOaep_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_Aes128Sha256RsaOaep_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_Aes128Sha256RsaOaep_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_Aes128Sha256RsaOaep_getRemotePlainTextBlockSize;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSig->verify = UA_SymSig_Aes128Sha256RsaOaep_verify;
    symSig->sign = UA_SymSig_Aes128Sha256RsaOaep_sign;
    symSig->getLocalSignatureSize = UA_SymSig_Aes128Sha256RsaOaep_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_Aes128Sha256RsaOaep_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_Aes128Sha256RsaOaep_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_Aes128Sha256RsaOaep_getRemoteKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEnc->encrypt = UA_SymEn_Aes128Sha256RsaOaep_encrypt;
    symEnc->decrypt = UA_SymEn_Aes128Sha256RsaOaep_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_Aes128Sha256RsaOaep_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_Aes128Sha256RsaOaep_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_Aes128Sha256RsaOaep_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_Aes128Sha256RsaOaep_getBlockSize;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = Aes128Sha256RsaOaep_New_Context;
    sp->deleteChannelContext = Aes128Sha256RsaOaep_Delete_Context;
    sp->setLocalSymEncryptingKey = UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = Aes128Sha256RsaOaep_setLocalSymSigningKey;
    sp->setLocalSymIv = UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymSigningKey;
    sp->setRemoteSymIv = UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymIv;
    sp->compareCertificate = UA_ChannelM_Aes128Sha256RsaOaep_compareCertificate;
    sp->generateKey = UA_Sym_Aes128Sha256RsaOaep_generateKey;
    sp->generateNonce = UA_Sym_Aes128Sha256RsaOaep_generateNonce;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_Aes128Sha256RsaOaep;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_Aes128Sha256RsaOaep;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep;
    sp->createSigningRequest = createSigningRequest_sp_aes128sha256rsaoaep;
    sp->clear = UA_Policy_Aes128Sha256RsaOaep_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate, EVP_PKEY_RSA);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_Aes128Sha256RsaOaep_New_Context(sp, localPrivateKey, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_aes256sha256rsapss.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Noel Graf)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN 66
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MAXASYMKEYLENGTH 512

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
} Policy_Context_Aes256Sha256RsaPss;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_Aes256Sha256RsaPss;

static UA_StatusCode
UA_Policy_Aes256Sha256RsaPss_New_Context(UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString localPrivateKey,
                                         const UA_Logger *logger) {
    Policy_Context_Aes256Sha256RsaPss *context =
        (Policy_Context_Aes256Sha256RsaPss *)UA_malloc(
            sizeof(Policy_Context_Aes256Sha256RsaPss));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    securityPolicy->policyContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_Aes256Sha256RsaPss_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    if(pc == NULL)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_aes128sha256rsapss(UA_SecurityPolicy *securityPolicy,
                                           const UA_String *subjectName,
                                           const UA_ByteString *nonce,
                                           const UA_KeyValueMap *params,
                                           UA_ByteString *csr,
                                           UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
     if(!securityPolicy->policyContext)
         return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss*)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey, &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_aes128sha256rsapss(UA_SecurityPolicy *securityPolicy,
                                                     const UA_ByteString newCertificate,
                                                     const UA_ByteString newPrivateKey) {
    if(!securityPolicy)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)securityPolicy->policyContext;

    UA_Boolean isLocalKey = false;
    if(newPrivateKey.length <= 0) {
        if(UA_CertificateUtils_comparePublicKeys(&newCertificate,
                                                 &securityPolicy->localCertificate) == 0)
            isLocalKey = true;
    }

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_StatusCode retval =
        UA_OpenSSL_LoadLocalCertificate(&newCertificate,
                                        &securityPolicy->localCertificate, EVP_PKEY_RSA);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    if(newPrivateKey.length > 0) {
        EVP_PKEY_free(pc->localPrivateKey);
        pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    } else {
        if(!isLocalKey) {
            EVP_PKEY_free(pc->localPrivateKey);
            pc->localPrivateKey = pc->csrLocalPrivateKey;
            pc->csrLocalPrivateKey = NULL;
        }
    }

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADNOTSUPPORTED;
        goto error;
    }

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_Aes256Sha256RsaPss_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
Aes256Sha256RsaPss_New_Context(const UA_SecurityPolicy *securityPolicy,
                               const UA_ByteString *remoteCertificate,
                               void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes256Sha256RsaPss *context =
        (Channel_Context_Aes256Sha256RsaPss *)UA_malloc(
            sizeof(Channel_Context_Aes256Sha256RsaPss));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval =
        UA_copyCertificate(&context->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&context->remoteCertificate, EVP_PKEY_RSA);
    if(context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear(&context->remoteCertificate);
        UA_free(context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
Aes256Sha256RsaPss_Delete_Context(const UA_SecurityPolicy *policy,
                                  void *channelContext) {
    if(channelContext == NULL)
        return;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_free(cc);
}

static UA_StatusCode
UA_AsySig_Aes256Sha256RsaPss_Verify(const UA_SecurityPolicy *policy, void *channelContext,
                                    const UA_ByteString *message,
                                    const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_RSA_PSS_SHA256_Verify(message, cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_compareCertificateThumbprint_Aes256Sha256RsaPss(const UA_SecurityPolicy *securityPolicy,
                                                   const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_Aes256Sha256RsaPss(const UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString *certificate,
                                                UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_Asym_Aes256Sha256RsaPss_Decrypt(const UA_SecurityPolicy *policy,
                                   void *channelContext, UA_ByteString *data) {
    if(data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    return UA_Openssl_RSA_Oaep_Sha2_Decrypt(data, pc->localPrivateKey);
}

static size_t
UA_Asym_Aes256Sha256RsaPss_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsySig_Aes256Sha256RsaPss_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                         const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_StatusCode retval =
        UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    if(retval != UA_STATUSCODE_GOOD ||
       keyLen <= (UA_Int32)UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN)
        return 0;
    return (size_t)keyLen - UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen * 8;
}

static UA_StatusCode
UA_Sym_Aes256Sha256RsaPss_generateNonce(const UA_SecurityPolicy *policy,
                                        void *channelContext, UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    if(rc != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymEn_Aes256Sha256RsaPss_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_Aes256Sha256RsaPss_generateKey(const UA_SecurityPolicy *policy,
                                      void *channelContext, const UA_ByteString *secret,
                                      const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out);
}

static UA_StatusCode
UA_CertSig_Aes256Sha256RsaPss_Verify(const UA_SecurityPolicy *policy, void *channelContext,
                                     const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(message, cc->remoteCertificateX509,
                                                  signature);
}

static UA_StatusCode
UA_CertSig_Aes256Sha256RsaPss_sign(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static size_t
UA_CertSig_Aes256Sha256RsaPss_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_CertSig_Aes256Sha256RsaPss_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen;
}

static UA_StatusCode
Aes256Sha256RsaPss_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
Aes256Sha256RsaPss_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                            void *channelContext,
                                            const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
Aes256Sha256RsaPss_setLocalSymIv(const UA_SecurityPolicy *policy,
                                 void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_Aes256Sha256RsaPss_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Aes256Sha256RsaPss_getBlockSize(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
Aes256Sha256RsaPss_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
Aes256Sha256RsaPss_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                             void *channelContext,
                                             const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
Aes256Sha256RsaPss_setRemoteSymIv(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsySig_Aes256Sha256RsaPss_sign(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *message,
                                  UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    return UA_Openssl_RSA_PSS_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymEn_Aes256Sha256RsaPss_encrypt(const UA_SecurityPolicy *policy,
                                     void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_Openssl_RSA_OAEP_SHA2_Encrypt(data,
                             UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN,
                                            cc->remoteCertificateX509);
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_Aes256Sha256RsaPss_verify(const UA_SecurityPolicy *policy, void *channelContext,
                                    const UA_ByteString *message,
                                    const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_Aes256Sha256RsaPss_sign(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *message,
                                  UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_Aes256Sha256RsaPss_decrypt(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_Aes256Sha256RsaPss_encrypt(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
Aes256Sha256RsaPss_compareCertificate(const UA_SecurityPolicy *policy,
                                      const void *channelContext,
                                      const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen * 8;
}

UA_StatusCode
UA_SecurityPolicy_Aes256Sha256RsaPss(UA_SecurityPolicy *sp,
                                      const UA_ByteString localCertificate,
                                      const UA_ByteString localPrivateKey,
                                      const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss\0");
    sp->certificateGroupId = UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(RSASHA256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 30;
    sp->policyType = UA_SECURITYPOLICYTYPE_RSA;

    /* Asymmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://opcfoundation.org/UA/security/rsa-pss-sha2-256\0");
    asymSig->verify = UA_AsySig_Aes256Sha256RsaPss_Verify;
    asymSig->sign = UA_AsySig_Aes256Sha256RsaPss_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_Aes256Sha256RsaPss_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_Aes256Sha256RsaPss_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("http://opcfoundation.org/UA/security/rsa-oaep-sha2-256\0");
    asymEnc->encrypt = UA_AsymEn_Aes256Sha256RsaPss_encrypt;
    asymEnc->decrypt = UA_Asym_Aes256Sha256RsaPss_Decrypt;
    asymEnc->getLocalKeyLength = UA_AsymEn_Aes256Sha256RsaPss_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_Aes256Sha256RsaPss_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_Aes256Sha256RsaPss_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_Aes256Sha256RsaPss_getRemotePlainTextBlockSize;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSig->verify = UA_SymSig_Aes256Sha256RsaPss_verify;
    symSig->sign = UA_SymSig_Aes256Sha256RsaPss_sign;
    symSig->getLocalSignatureSize = UA_SymSig_Aes256Sha256RsaPss_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_Aes256Sha256RsaPss_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_Aes256Sha256RsaPss_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_Aes256Sha256RsaPss_getRemoteKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = UA_SymEn_Aes256Sha256RsaPss_encrypt;
    symEnc->decrypt = UA_SymEn_Aes256Sha256RsaPss_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_Aes256Sha256RsaPss_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_Aes256Sha256RsaPss_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_Aes256Sha256RsaPss_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_Aes256Sha256RsaPss_getBlockSize;

    /* Certificate Signing */
    UA_SecurityPolicySignatureAlgorithm *certSig = &sp->certSignatureAlgorithm;
    certSig->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    certSig->verify = UA_CertSig_Aes256Sha256RsaPss_Verify;
    certSig->sign = UA_CertSig_Aes256Sha256RsaPss_sign;
    certSig->getLocalSignatureSize = UA_CertSig_Aes256Sha256RsaPss_getLocalSignatureSize;
    certSig->getRemoteSignatureSize = UA_CertSig_Aes256Sha256RsaPss_getRemoteSignatureSize;

    /* Direct Method Pointers */
    sp->newChannelContext = Aes256Sha256RsaPss_New_Context;
    sp->deleteChannelContext = Aes256Sha256RsaPss_Delete_Context;
    sp->setLocalSymEncryptingKey = Aes256Sha256RsaPss_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = Aes256Sha256RsaPss_setLocalSymSigningKey;
    sp->setLocalSymIv = Aes256Sha256RsaPss_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = Aes256Sha256RsaPss_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = Aes256Sha256RsaPss_setRemoteSymSigningKey;
    sp->setRemoteSymIv = Aes256Sha256RsaPss_setRemoteSymIv;
    sp->compareCertificate = Aes256Sha256RsaPss_compareCertificate;
    sp->generateKey = UA_Sym_Aes256Sha256RsaPss_generateKey;
    sp->generateNonce = UA_Sym_Aes256Sha256RsaPss_generateNonce;
    sp->nonceLength = 32;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_Aes256Sha256RsaPss;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_Aes256Sha256RsaPss;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_aes128sha256rsapss;
    sp->createSigningRequest = createSigningRequest_sp_aes128sha256rsapss;
    sp->clear = UA_Policy_Aes256Sha256RsaPss_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_RSA);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_Aes256Sha256RsaPss_New_Context(sp, localPrivateKey, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_eccnistp256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH 64
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH 16
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP256_NONCE_LENGTH_BYTES 64

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccNistP256;

typedef struct Channel_Context_EccNistP256 {
    EVP_PKEY *    localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_EccNistP256;

static UA_StatusCode
UA_Policy_EccNistP256_New_Context(UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString localPrivateKey,
                                  const UA_ApplicationType applicationType,
                                  const UA_Logger *logger) {
    Policy_Context_EccNistP256 *context = (Policy_Context_EccNistP256 *)
        UA_malloc(sizeof(Policy_Context_EccNistP256));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccNistP256_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    /* Delete all allocated members in the context */
    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)policy->policyContext;
    if(!pc)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccnistp256(UA_SecurityPolicy *securityPolicy,
                                    const UA_String *subjectName,
                                    const UA_ByteString *nonce,
                                    const UA_KeyValueMap *params,
                                    UA_ByteString *csr,
                                    UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
     if(!securityPolicy->policyContext)
         return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256*)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccNistP256(UA_SecurityPolicy *securityPolicy,
                                              const UA_ByteString newCertificate,
                                              const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)securityPolicy->policyContext;

    /* Set the certificate */
    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate,
        EVP_PKEY_EC);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Update the thumbprint */
    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccNistP256_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccNistP256_New_Context(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *remoteCertificate,
                                         void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP256 *newContext = (Channel_Context_EccNistP256 *)
        UA_calloc(1, sizeof(Channel_Context_EccNistP256));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&newContext->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    /* Decode to X509 */
    newContext->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&newContext->remoteCertificate, EVP_PKEY_EC);
    if(newContext->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&newContext->remoteCertificate);
        UA_free (newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    /* Return the new channel context */
    *channelContext = newContext;

    return UA_STATUSCODE_GOOD;
}

static void
EccNistP256_Delete_Context(const UA_SecurityPolicy *policy,
                           void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccNistP256 *cc =
        (Channel_Context_EccNistP256 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccNistP256(const UA_SecurityPolicy *policy,
                                            const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccNistP256(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *certificate,
                                         UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static size_t
UA_Asym_EccNistP256_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    /* According to the standard, the server and the client must agree on the
     * security mode and security policy. Therefore, it can be assumed that
     * the remote asymmetric cryptographic tokens have the same sizes as the
     * local ones. */
    return UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccNistP256_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccNistP256_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    /* According to the standard, the server and the client must agree on the
     * security mode and security policy. Therefore, it can be assumed that the
     * remote asymmetric cryptographic tokens have the same sizes as the local
     * ones.
     *
     * No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

static UA_StatusCode
UA_Sym_EccNistP256_generateNonce(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *out) {
    Policy_Context_EccNistP256* pctx = (Policy_Context_EccNistP256*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Detect if we want to create an ephemeral key or just cryptographic random
     * data */
    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccNistP256 *cctx = (Channel_Context_EccNistP256*)channelContext;
        return UA_OpenSSL_ECC_NISTP256_GenerateKey(&cctx->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccNistP256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccNistP256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccNistP256_generateKey(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *secret,
                               const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccNistP256* pctx = (Policy_Context_EccNistP256 *)policy->policyContext;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_ECC_DeriveKeys(EC_curve_nist2nid("P-256"), "SHA256",
                                     pctx->applicationType, cc->localEphemeralKeyPair,
                                     secret, seed, out);
}

static UA_StatusCode
EccNistP256_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                                   void *channelContext,
                                                   const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccNistP256_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccNistP256_setLocalSymIv(const UA_SecurityPolicy *policy,
                          void *channelContext,
                          const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccNistP256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccNistP256_getBlockSize(const UA_SecurityPolicy *policy,
                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccNistP256_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccNistP256_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                   void *channelContext,
                                   const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccNistP256_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccNistP256_setRemoteSymIv(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccNistP256_sign(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256 *pc =
        (Policy_Context_EccNistP256 *)policy->policyContext;
    return UA_Openssl_ECDSA_SHA256_Sign(message, pc->localPrivateKey, signature);
}


static UA_StatusCode
UA_AsymSig_EccNistP256_verify(const UA_SecurityPolicy *policy, void *channelContext,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_Openssl_ECDSA_SHA256_Verify(message, cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccNistP256_Dummy(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD; /* Do nothing and return true */
}

static size_t
UA_SymSig_EccNistP256_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccNistP256_verify(const UA_SecurityPolicy *policy, void *channelContext,
                             const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccNistP256_sign(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccNistP256_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccNistP256_decrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_EccNistP256_encrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
EccNistP256_compareCertificate(const UA_SecurityPolicy *policy,
                               const void *channelContext,
                               const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccNistP256 *cc =
        (const Channel_Context_EccNistP256 *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_EccNistP256_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    /* No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccNistP256(UA_SecurityPolicy *sp,
                              const UA_ApplicationType applicationType,
                              const UA_ByteString localCertificate,
                              const UA_ByteString localPrivateKey,
                              const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_nistP256 is deprecated (OPC UA Part 7); "
                   "use ECC_nistP256_AesGcm or ECC_nistP256_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCNISTP256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    /* Asymmetric Signature
     * TODO: The Softing SDK works when we send an empty string. It does not
     * work with either of the following:
     * asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256\0");
     * asySigAlgorithm->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2473\0"); */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccNistP256_verify;
    asymSig->sign = UA_AsymSig_EccNistP256_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccNistP256_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccNistP256_getRemoteSignatureSize;

    /* Asymmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccNistP256_Dummy;
    asymEnc->decrypt = UA_Asym_EccNistP256_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccNistP256_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccNistP256_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccNistP256_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccNistP256_getRemotePlainTextBlockSize;

    /* Symmetric Signature */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSig->verify = UA_SymSig_EccNistP256_verify;
    symSig->sign = UA_SymSig_EccNistP256_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccNistP256_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccNistP256_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccNistP256_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccNistP256_getRemoteKeyLength;

    /* Symmetric Encryption */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEnc->encrypt = UA_SymEn_EccNistP256_encrypt;
    symEnc->decrypt = UA_SymEn_EccNistP256_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccNistP256_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccNistP256_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccNistP256_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccNistP256_getBlockSize;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = EccNistP256_New_Context;
    sp->deleteChannelContext = EccNistP256_Delete_Context;
    sp->setLocalSymEncryptingKey = EccNistP256_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccNistP256_setLocalSymSigningKey;
    sp->setLocalSymIv = EccNistP256_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccNistP256_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccNistP256_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccNistP256_setRemoteSymIv;
    sp->compareCertificate = EccNistP256_compareCertificate;
    sp->generateKey = UA_Sym_EccNistP256_generateKey;
    sp->generateNonce = UA_Sym_EccNistP256_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCNISTP256_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccNistP256;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccNistP256;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccNistP256;
    sp->createSigningRequest = createSigningRequest_sp_eccnistp256;
    sp->clear = UA_Policy_EccNistP256_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_EC);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_EccNistP256_New_Context(sp, localPrivateKey, applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_eccnistp256_aesgcm.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *
 * SecurityPolicy [ECC A] – ECC-nistP256-AesGcm Profile
 *   http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_AesGcm
 *
 * This is the new (non-deprecated) profile, supersedes
 *   http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256
 * Differences from the deprecated policy:
 *   - Symmetric signing/encryption: HMAC-SHA2-256 + AES-128-CBC
 *     replaced by AES-128-GCM AEAD (16-byte tag, 12-byte IV).
 *   - Policy type: UA_SECURITYPOLICYTYPE_ECC_AEAD (was _ECC).
 *   - Adds setMessageSecurityParameters for AEAD nonce masking.
 * Asymmetric signature (ECDSA-SHA2-256) and key derivation
 * (HKDF-SHA2-256 over P-256 ECDHE) are unchanged.
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_SECURITYPOLICY_ECCNISTP256_AESGCM_ASYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP256_AESGCM_ASYM_SIGNATURE_LENGTH 64
#define UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_ENCRYPTION_KEY_LENGTH 16
/* AES-128-GCM is an AEAD cipher: there is NO separate symmetric signing
 * key. The derived key material is only [EncryptionKey(16) | IV(12)] =
 * 28 bytes, and the GCM authentication tag is produced with the
 * encryption key. (OPC UA Part 6 v1.05: ECC_nistP256_AesGcm has
 * DerivedSignatureKeyLength = 0; cf. UA-.NETStandard SecurityPolicyInfo.) */
#define UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNING_KEY_LENGTH 0
#define UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH 16
#define UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_IV_LENGTH 12
#define UA_SECURITYPOLICY_ECCNISTP256_AESGCM_NONCE_LENGTH_BYTES 64

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccNistP256AesGcm;

typedef struct Channel_Context_EccNistP256AesGcm {
    EVP_PKEY *    localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */

    /* AEAD message context (mirrors securitypolicy_ecccurve448.c) */
    UA_UInt32 tokenId;
    UA_UInt32 previousSequenceNumber;
    UA_ByteString additionalAuthData;
} Channel_Context_EccNistP256AesGcm;

/* Compute the per-message AES-128-GCM IV.
 * For GCM, the 12-byte IV is formed by XORing the tokenId into the first
 * 4 bytes and the previous sequence number into the next 4 bytes of the
 * base (local/remote) Sym IV. The last 4 bytes are unchanged. */
static void
computeMaskedIvAesGcm(UA_Byte *iv_out, const UA_ByteString *base_iv,
                      UA_UInt32 tokenId, UA_UInt32 seqNo) {
    memcpy(iv_out, base_iv->data, 12);
    iv_out[0] ^= (UA_Byte)(tokenId & 0xFF);
    iv_out[1] ^= (UA_Byte)((tokenId >> 8) & 0xFF);
    iv_out[2] ^= (UA_Byte)((tokenId >> 16) & 0xFF);
    iv_out[3] ^= (UA_Byte)((tokenId >> 24) & 0xFF);
    iv_out[4] ^= (UA_Byte)(seqNo & 0xFF);
    iv_out[5] ^= (UA_Byte)((seqNo >> 8) & 0xFF);
    iv_out[6] ^= (UA_Byte)((seqNo >> 16) & 0xFF);
    iv_out[7] ^= (UA_Byte)((seqNo >> 24) & 0xFF);
}

/* --- Policy Context --- */

static UA_StatusCode
UA_Policy_EccNistP256AesGcm_New_Context(UA_SecurityPolicy *securityPolicy,
                                        const UA_ByteString localPrivateKey,
                                        const UA_ApplicationType applicationType,
                                        const UA_Logger *logger) {
    Policy_Context_EccNistP256AesGcm *context = (Policy_Context_EccNistP256AesGcm *)
        UA_malloc(sizeof(Policy_Context_EccNistP256AesGcm));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccNistP256AesGcm_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    /* Delete all allocated members in the context */
    Policy_Context_EccNistP256AesGcm *pc =
        (Policy_Context_EccNistP256AesGcm *)policy->policyContext;
    if(!pc)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccnistp256aesgcm(UA_SecurityPolicy *securityPolicy,
                                          const UA_String *subjectName,
                                          const UA_ByteString *nonce,
                                          const UA_KeyValueMap *params,
                                          UA_ByteString *csr,
                                          UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
     if(!securityPolicy->policyContext)
         return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256AesGcm *pc =
        (Policy_Context_EccNistP256AesGcm*)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccNistP256AesGcm(UA_SecurityPolicy *securityPolicy,
                                                    const UA_ByteString newCertificate,
                                                    const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccNistP256AesGcm *pc =
        (Policy_Context_EccNistP256AesGcm *)securityPolicy->policyContext;

    /* Set the certificate */
    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate,
        EVP_PKEY_EC);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Update the thumbprint */
    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccNistP256AesGcm_Clear_Context(securityPolicy);
    return retval;
}

/* --- Channel Context --- */

static UA_StatusCode
EccNistP256AesGcm_New_Context(const UA_SecurityPolicy *securityPolicy,
                              const UA_ByteString *remoteCertificate,
                              void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP256AesGcm *newContext = (Channel_Context_EccNistP256AesGcm *)
        UA_calloc(1, sizeof(Channel_Context_EccNistP256AesGcm));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&newContext->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    /* Decode to X509 */
    newContext->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&newContext->remoteCertificate, EVP_PKEY_EC);
    if(newContext->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&newContext->remoteCertificate);
        UA_free (newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    /* Return the new channel context */
    *channelContext = newContext;

    return UA_STATUSCODE_GOOD;
}

static void
EccNistP256AesGcm_Delete_Context(const UA_SecurityPolicy *policy,
                                 void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_ByteString_clear(&cc->additionalAuthData);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

/* --- AEAD Message Security Parameters --- */

static UA_StatusCode
EccNistP256AesGcm_setMessageSecurityParameters(const UA_SecurityPolicy *policy,
                                                void *channelContext,
                                                UA_UInt32 tokenId,
                                                UA_UInt32 previousSequenceNumber,
                                                const UA_ByteString *additionalAuthData) {
    if(!channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    cc->tokenId = tokenId;
    cc->previousSequenceNumber = previousSequenceNumber;

    UA_ByteString_clear(&cc->additionalAuthData);
    if(additionalAuthData && additionalAuthData->length > 0)
        return UA_ByteString_copy(additionalAuthData, &cc->additionalAuthData);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccNistP256AesGcm(const UA_SecurityPolicy *policy,
                                                  const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccNistP256AesGcm *pc =
        (Policy_Context_EccNistP256AesGcm *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccNistP256AesGcm(const UA_SecurityPolicy *securityPolicy,
                                               const UA_ByteString *certificate,
                                               UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static size_t
UA_Asym_EccNistP256AesGcm_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    /* According to the standard, the server and the client must agree on the
     * security mode and security policy. Therefore, it can be assumed that
     * the remote asymmetric cryptographic tokens have the same sizes as the
     * local ones. */
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccNistP256AesGcm_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccNistP256AesGcm_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                        const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256AesGcm_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256AesGcm_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    /* According to the standard, the server and the client must agree on the
     * security mode and security policy. Therefore, it can be assumed that the
     * remote asymmetric cryptographic tokens have the same sizes as the local
     * ones.
     *
     * No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

static UA_StatusCode
UA_Sym_EccNistP256AesGcm_generateNonce(const UA_SecurityPolicy *policy,
                                       void *channelContext, UA_ByteString *out) {
    Policy_Context_EccNistP256AesGcm* pctx =
        (Policy_Context_EccNistP256AesGcm*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Detect if we want to create an ephemeral key or just cryptographic random
     * data */
    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccNistP256AesGcm *cctx =
            (Channel_Context_EccNistP256AesGcm*)channelContext;
        return UA_OpenSSL_ECC_NISTP256_GenerateKey(&cctx->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccNistP256AesGcm_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccNistP256AesGcm_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccNistP256AesGcm_generateKey(const UA_SecurityPolicy *policy,
                                     void *channelContext, const UA_ByteString *secret,
                                     const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccNistP256AesGcm* pctx =
        (Policy_Context_EccNistP256AesGcm *)policy->policyContext;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_ECC_DeriveKeys(EC_curve_nist2nid("P-256"), "SHA256",
                                     pctx->applicationType, cc->localEphemeralKeyPair,
                                     secret, seed, out);
}

static UA_StatusCode
EccNistP256AesGcm_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccNistP256AesGcm_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                           void *channelContext,
                                           const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccNistP256AesGcm_setLocalSymIv(const UA_SecurityPolicy *policy,
                                void *channelContext,
                                const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccNistP256AesGcm_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccNistP256AesGcm_getBlockSize(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    /* AEAD ciphers are stream-like -> 1 byte */
    return 1;
}

static size_t
UA_SymEn_EccNistP256AesGcm_getIvLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_IV_LENGTH;
}

static size_t
UA_SymSig_EccNistP256AesGcm_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccNistP256AesGcm_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccNistP256AesGcm_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                            void *channelContext,
                                            const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccNistP256AesGcm_setRemoteSymIv(const UA_SecurityPolicy *policy,
                                 void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

/* --- Asymmetric Signature (ECDSA-SHA2-256, unchanged from the deprecated
 *     policy) --- */

static UA_StatusCode
UA_AsymSig_EccNistP256AesGcm_sign(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *message,
                                  UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256AesGcm *pc =
        (Policy_Context_EccNistP256AesGcm *)policy->policyContext;
    return UA_Openssl_ECDSA_SHA256_Sign(message, pc->localPrivateKey, signature);
}


static UA_StatusCode
UA_AsymSig_EccNistP256AesGcm_verify(const UA_SecurityPolicy *policy, void *channelContext,
                                    const UA_ByteString *message,
                                    const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;
    return UA_Openssl_ECDSA_SHA256_Verify(message, cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccNistP256AesGcm_Dummy(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD; /* Do nothing and return true */
}

/* --- Symmetric Signature (AES-128-GCM AEAD, sign-only) --- */

static size_t
UA_SymSig_EccNistP256AesGcm_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccNistP256AesGcm_verify(const UA_SecurityPolicy *policy, void *channelContext,
                                   const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(signature->length < UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;

    /* Compute masked IV using the remote IV */
    UA_Byte maskedIv[12];
    computeMaskedIvAesGcm(maskedIv, &cc->remoteSymIv,
                          cc->tokenId, cc->previousSequenceNumber);

    /* Use AES-128-GCM AEAD to verify the GCM tag.
     * Treat the entire message as AAD (sign-only). The AEAD tag is
     * produced/verified with the encryption key (no separate signing
     * key for AEAD policies). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_DecryptInit_ex(ctx, NULL, NULL,
                          cc->remoteSymEncryptingKey.data, maskedIv) != 1)
        goto errout;

    /* Set the expected tag for verification */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
                           UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH,
                           (void*)(uintptr_t)signature->data) != 1)
        goto errout;

    /* Process the entire message as AAD */
    int outl = 0;
    if(EVP_DecryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize triggers tag verification */
    UA_Byte dummy;
    if(EVP_DecryptFinal_ex(ctx, &dummy, &outl) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto errout;
    }
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

static UA_StatusCode
UA_SymSig_EccNistP256AesGcm_sign(const UA_SecurityPolicy *policy,
                                 void *channelContext, const UA_ByteString *message,
                                 UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(signature->length < UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;

    /* Compute masked IV (same nonce derivation as encrypt mode) */
    UA_Byte maskedIv[12];
    computeMaskedIvAesGcm(maskedIv, &cc->localSymIv,
                          cc->tokenId, cc->previousSequenceNumber);

    /* Use AES-128-GCM AEAD to compute the GCM tag.
     * For sign-only: treat the entire message as AAD (no encryption).
     * The AEAD tag is produced with the encryption key (no separate
     * signing key for AEAD policies). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_EncryptInit_ex(ctx, NULL, NULL,
                          cc->localSymEncryptingKey.data, maskedIv) != 1)
        goto errout;

    /* Process the entire message as AAD (authenticated, not encrypted) */
    int outl = 0;
    if(EVP_EncryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize with no plaintext */
    UA_Byte dummy;
    if(EVP_EncryptFinal_ex(ctx, &dummy, &outl) != 1)
        goto errout;

    /* Get the 16-byte GCM authentication tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG,
                           UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH,
                           signature->data) != 1)
        goto errout;
    signature->length = UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH;
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

static size_t
UA_SymSig_EccNistP256AesGcm_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_AESGCM_SYM_SIGNATURE_LENGTH;
}

/* --- Symmetric Encryption (AES-128-GCM AEAD) --- */

static UA_StatusCode
UA_SymEn_EccNistP256AesGcm_decrypt(const UA_SecurityPolicy *policy,
                                   void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;

    UA_Byte maskedIv[12];
    computeMaskedIvAesGcm(maskedIv, &cc->remoteSymIv,
                          cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_AES_128_GCM_Decrypt(
        &ivBs, &cc->remoteSymEncryptingKey, &cc->additionalAuthData,
        data, true);
}

static UA_StatusCode
UA_SymEn_EccNistP256AesGcm_encrypt(const UA_SecurityPolicy *policy,
                                   void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256AesGcm *cc =
        (Channel_Context_EccNistP256AesGcm *)channelContext;

    UA_Byte maskedIv[12];
    computeMaskedIvAesGcm(maskedIv, &cc->localSymIv,
                          cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_AES_128_GCM_Encrypt(
        &ivBs, &cc->localSymEncryptingKey, &cc->additionalAuthData,
        data, true);
}

static UA_StatusCode
EccNistP256AesGcm_compareCertificate(const UA_SecurityPolicy *policy,
                                     const void *channelContext,
                                     const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccNistP256AesGcm *cc =
        (const Channel_Context_EccNistP256AesGcm *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_EccNistP256AesGcm_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    /* No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

/* --- Public Entry Point --- */

UA_StatusCode
UA_SecurityPolicy_EccNistP256AesGcm(UA_SecurityPolicy *sp,
                                    const UA_ApplicationType applicationType,
                                    const UA_ByteString localCertificate,
                                    const UA_ByteString localPrivateKey,
                                    const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_AesGcm\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCNISTP256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC_AEAD;

    /* Asymmetric Signature (ECDSA-SHA2-256).
     *
     * The URI here is what goes into the SignatureData.algorithm of the
     * CreateSession/ActivateSession signatures. For the ECC SecurityPolicies
     * the OPC UA reference stack (UA-.NETStandard) signs with an empty
     * algorithm but its verifier accepts EITHER an empty string OR the
     * SecurityPolicy URI (SecurityPolicies.cs, AsymmetricSignatureAlgorithm
     * EcdsaSha256: `IsNullOrEmpty(signature.Algorithm) || signature.Algorithm
     * == securityPolicy.Uri`). Empty is accepted by .NET/Softing but rejected
     * by stricter servers (e.g. CodeSys), so we send the SecurityPolicy URI -
     * the canonical non-empty value that interoperates with both. The
     * dedicated ECDSA URIs (xmldsig-more#ecdsa-sha256, conformanceunit/2473)
     * are NOT accepted and must not be used. */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_AesGcm\0");
    asymSig->verify = UA_AsymSig_EccNistP256AesGcm_verify;
    asymSig->sign = UA_AsymSig_EccNistP256AesGcm_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccNistP256AesGcm_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccNistP256AesGcm_getRemoteSignatureSize;

    /* Asymmetric Encryption (none) */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccNistP256AesGcm_Dummy;
    asymEnc->decrypt = UA_Asym_EccNistP256AesGcm_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccNistP256AesGcm_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccNistP256AesGcm_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccNistP256AesGcm_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccNistP256AesGcm_getRemotePlainTextBlockSize;

    /* Symmetric Signature (AES-128-GCM, 16-byte tag) */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://opcfoundation.org/UA/security/aes128-gcm\0");
    symSig->verify = UA_SymSig_EccNistP256AesGcm_verify;
    symSig->sign = UA_SymSig_EccNistP256AesGcm_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccNistP256AesGcm_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccNistP256AesGcm_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccNistP256AesGcm_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccNistP256AesGcm_getRemoteKeyLength;

    /* Symmetric Encryption (AES-128-GCM AEAD) */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://opcfoundation.org/UA/security/aes128-gcm\0");
    symEnc->encrypt = UA_SymEn_EccNistP256AesGcm_encrypt;
    symEnc->decrypt = UA_SymEn_EccNistP256AesGcm_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccNistP256AesGcm_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccNistP256AesGcm_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccNistP256AesGcm_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccNistP256AesGcm_getBlockSize;
    symEnc->getLocalIvLength = UA_SymEn_EccNistP256AesGcm_getIvLength;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = EccNistP256AesGcm_New_Context;
    sp->deleteChannelContext = EccNistP256AesGcm_Delete_Context;
    sp->setLocalSymEncryptingKey = EccNistP256AesGcm_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccNistP256AesGcm_setLocalSymSigningKey;
    sp->setLocalSymIv = EccNistP256AesGcm_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccNistP256AesGcm_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccNistP256AesGcm_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccNistP256AesGcm_setRemoteSymIv;
    sp->setMessageSecurityParameters = EccNistP256AesGcm_setMessageSecurityParameters;
    sp->compareCertificate = EccNistP256AesGcm_compareCertificate;
    sp->generateKey = UA_Sym_EccNistP256AesGcm_generateKey;
    sp->generateNonce = UA_Sym_EccNistP256AesGcm_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCNISTP256_AESGCM_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccNistP256AesGcm;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccNistP256AesGcm;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccNistP256AesGcm;
    sp->createSigningRequest = createSigningRequest_sp_eccnistp256aesgcm;
    sp->clear = UA_Policy_EccNistP256AesGcm_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_EC);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_EccNistP256AesGcm_New_Context(sp, localPrivateKey,
                                                  applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_eccnistp256_chachapoly.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *
 * SecurityPolicy [ECC A] – ECC-nistP256-ChaChaPoly Profile
 *   http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_ChaChaPoly
 *
 * This is the new (non-deprecated) profile, supersedes
 *   http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256
 * Differences from the deprecated policy:
 *   - Symmetric signing/encryption: HMAC-SHA2-256 + AES-128-CBC
 *     replaced by ChaCha20-Poly1305 AEAD (16-byte tag, 12-byte nonce).
 *   - Policy type: UA_SECURITYPOLICYTYPE_ECC_AEAD (was _ECC).
 *   - Adds setMessageSecurityParameters for AEAD nonce masking.
 * Asymmetric signature (ECDSA-SHA2-256) and key derivation
 * (HKDF-SHA2-256 over P-256 ECDHE) are unchanged.
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_ASYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_ASYM_SIGNATURE_LENGTH 64
#define UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_ENCRYPTION_KEY_LENGTH 32
/* ChaCha20-Poly1305 is an AEAD cipher: there is NO separate symmetric signing
 * key. The derived key material is only [EncryptionKey(16) | IV(12)] =
 * 28 bytes, and the GCM authentication tag is produced with the
 * encryption key. (OPC UA Part 6 v1.05: ECC_nistP256_ChaChaPoly has
 * DerivedSignatureKeyLength = 0; cf. UA-.NETStandard SecurityPolicyInfo.) */
#define UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNING_KEY_LENGTH 0
#define UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH 16
#define UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_IV_LENGTH 12
#define UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_NONCE_LENGTH_BYTES 64

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccNistP256ChaChaPoly;

typedef struct Channel_Context_EccNistP256ChaChaPoly {
    EVP_PKEY *    localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */

    /* AEAD message context (mirrors securitypolicy_ecccurve448.c) */
    UA_UInt32 tokenId;
    UA_UInt32 previousSequenceNumber;
    UA_ByteString additionalAuthData;
} Channel_Context_EccNistP256ChaChaPoly;

/* Compute the per-message ChaCha20-Poly1305 nonce.
 * For GCM, the 12-byte IV is formed by XORing the tokenId into the first
 * 4 bytes and the previous sequence number into the next 4 bytes of the
 * base (local/remote) Sym IV. The last 4 bytes are unchanged. */
static void
computeMaskedIvChaChaPoly(UA_Byte *iv_out, const UA_ByteString *base_iv,
                      UA_UInt32 tokenId, UA_UInt32 seqNo) {
    memcpy(iv_out, base_iv->data, 12);
    iv_out[0] ^= (UA_Byte)(tokenId & 0xFF);
    iv_out[1] ^= (UA_Byte)((tokenId >> 8) & 0xFF);
    iv_out[2] ^= (UA_Byte)((tokenId >> 16) & 0xFF);
    iv_out[3] ^= (UA_Byte)((tokenId >> 24) & 0xFF);
    iv_out[4] ^= (UA_Byte)(seqNo & 0xFF);
    iv_out[5] ^= (UA_Byte)((seqNo >> 8) & 0xFF);
    iv_out[6] ^= (UA_Byte)((seqNo >> 16) & 0xFF);
    iv_out[7] ^= (UA_Byte)((seqNo >> 24) & 0xFF);
}

/* --- Policy Context --- */

static UA_StatusCode
UA_Policy_EccNistP256ChaChaPoly_New_Context(UA_SecurityPolicy *securityPolicy,
                                        const UA_ByteString localPrivateKey,
                                        const UA_ApplicationType applicationType,
                                        const UA_Logger *logger) {
    Policy_Context_EccNistP256ChaChaPoly *context = (Policy_Context_EccNistP256ChaChaPoly *)
        UA_malloc(sizeof(Policy_Context_EccNistP256ChaChaPoly));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccNistP256ChaChaPoly_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    /* Delete all allocated members in the context */
    Policy_Context_EccNistP256ChaChaPoly *pc =
        (Policy_Context_EccNistP256ChaChaPoly *)policy->policyContext;
    if(!pc)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccnistp256chachapoly(UA_SecurityPolicy *securityPolicy,
                                          const UA_String *subjectName,
                                          const UA_ByteString *nonce,
                                          const UA_KeyValueMap *params,
                                          UA_ByteString *csr,
                                          UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
     if(!securityPolicy->policyContext)
         return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256ChaChaPoly *pc =
        (Policy_Context_EccNistP256ChaChaPoly*)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccNistP256ChaChaPoly(UA_SecurityPolicy *securityPolicy,
                                                    const UA_ByteString newCertificate,
                                                    const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccNistP256ChaChaPoly *pc =
        (Policy_Context_EccNistP256ChaChaPoly *)securityPolicy->policyContext;

    /* Set the certificate */
    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate,
        EVP_PKEY_EC);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Update the thumbprint */
    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccNistP256ChaChaPoly_Clear_Context(securityPolicy);
    return retval;
}

/* --- Channel Context --- */

static UA_StatusCode
EccNistP256ChaChaPoly_New_Context(const UA_SecurityPolicy *securityPolicy,
                              const UA_ByteString *remoteCertificate,
                              void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP256ChaChaPoly *newContext = (Channel_Context_EccNistP256ChaChaPoly *)
        UA_calloc(1, sizeof(Channel_Context_EccNistP256ChaChaPoly));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&newContext->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    /* Decode to X509 */
    newContext->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&newContext->remoteCertificate, EVP_PKEY_EC);
    if(newContext->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&newContext->remoteCertificate);
        UA_free (newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    /* Return the new channel context */
    *channelContext = newContext;

    return UA_STATUSCODE_GOOD;
}

static void
EccNistP256ChaChaPoly_Delete_Context(const UA_SecurityPolicy *policy,
                                 void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_ByteString_clear(&cc->additionalAuthData);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

/* --- AEAD Message Security Parameters --- */

static UA_StatusCode
EccNistP256ChaChaPoly_setMessageSecurityParameters(const UA_SecurityPolicy *policy,
                                                void *channelContext,
                                                UA_UInt32 tokenId,
                                                UA_UInt32 previousSequenceNumber,
                                                const UA_ByteString *additionalAuthData) {
    if(!channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    cc->tokenId = tokenId;
    cc->previousSequenceNumber = previousSequenceNumber;

    UA_ByteString_clear(&cc->additionalAuthData);
    if(additionalAuthData && additionalAuthData->length > 0)
        return UA_ByteString_copy(additionalAuthData, &cc->additionalAuthData);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccNistP256ChaChaPoly(const UA_SecurityPolicy *policy,
                                                  const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccNistP256ChaChaPoly *pc =
        (Policy_Context_EccNistP256ChaChaPoly *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccNistP256ChaChaPoly(const UA_SecurityPolicy *securityPolicy,
                                               const UA_ByteString *certificate,
                                               UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static size_t
UA_Asym_EccNistP256ChaChaPoly_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    /* According to the standard, the server and the client must agree on the
     * security mode and security policy. Therefore, it can be assumed that
     * the remote asymmetric cryptographic tokens have the same sizes as the
     * local ones. */
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccNistP256ChaChaPoly_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccNistP256ChaChaPoly_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                        const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256ChaChaPoly_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP256ChaChaPoly_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    /* According to the standard, the server and the client must agree on the
     * security mode and security policy. Therefore, it can be assumed that the
     * remote asymmetric cryptographic tokens have the same sizes as the local
     * ones.
     *
     * No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

static UA_StatusCode
UA_Sym_EccNistP256ChaChaPoly_generateNonce(const UA_SecurityPolicy *policy,
                                       void *channelContext, UA_ByteString *out) {
    Policy_Context_EccNistP256ChaChaPoly* pctx =
        (Policy_Context_EccNistP256ChaChaPoly*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Detect if we want to create an ephemeral key or just cryptographic random
     * data */
    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccNistP256ChaChaPoly *cctx =
            (Channel_Context_EccNistP256ChaChaPoly*)channelContext;
        return UA_OpenSSL_ECC_NISTP256_GenerateKey(&cctx->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccNistP256ChaChaPoly_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccNistP256ChaChaPoly_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccNistP256ChaChaPoly_generateKey(const UA_SecurityPolicy *policy,
                                     void *channelContext, const UA_ByteString *secret,
                                     const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccNistP256ChaChaPoly* pctx =
        (Policy_Context_EccNistP256ChaChaPoly *)policy->policyContext;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_ECC_DeriveKeys(EC_curve_nist2nid("P-256"), "SHA256",
                                     pctx->applicationType, cc->localEphemeralKeyPair,
                                     secret, seed, out);
}

static UA_StatusCode
EccNistP256ChaChaPoly_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccNistP256ChaChaPoly_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                           void *channelContext,
                                           const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccNistP256ChaChaPoly_setLocalSymIv(const UA_SecurityPolicy *policy,
                                void *channelContext,
                                const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccNistP256ChaChaPoly_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccNistP256ChaChaPoly_getBlockSize(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    /* AEAD ciphers are stream-like -> 1 byte */
    return 1;
}

static size_t
UA_SymEn_EccNistP256ChaChaPoly_getIvLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_IV_LENGTH;
}

static size_t
UA_SymSig_EccNistP256ChaChaPoly_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccNistP256ChaChaPoly_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccNistP256ChaChaPoly_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                            void *channelContext,
                                            const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccNistP256ChaChaPoly_setRemoteSymIv(const UA_SecurityPolicy *policy,
                                 void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

/* --- Asymmetric Signature (ECDSA-SHA2-256, unchanged from the deprecated
 *     policy) --- */

static UA_StatusCode
UA_AsymSig_EccNistP256ChaChaPoly_sign(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *message,
                                  UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP256ChaChaPoly *pc =
        (Policy_Context_EccNistP256ChaChaPoly *)policy->policyContext;
    return UA_Openssl_ECDSA_SHA256_Sign(message, pc->localPrivateKey, signature);
}


static UA_StatusCode
UA_AsymSig_EccNistP256ChaChaPoly_verify(const UA_SecurityPolicy *policy, void *channelContext,
                                    const UA_ByteString *message,
                                    const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    return UA_Openssl_ECDSA_SHA256_Verify(message, cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccNistP256ChaChaPoly_Dummy(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD; /* Do nothing and return true */
}

/* --- Symmetric Signature (ChaCha20-Poly1305 AEAD, sign-only) --- */

static size_t
UA_SymSig_EccNistP256ChaChaPoly_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccNistP256ChaChaPoly_verify(const UA_SecurityPolicy *policy, void *channelContext,
                                   const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(signature->length < UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;

    /* Compute masked IV using the remote IV */
    UA_Byte maskedIv[12];
    computeMaskedIvChaChaPoly(maskedIv, &cc->remoteSymIv,
                          cc->tokenId, cc->previousSequenceNumber);

    /* Use ChaCha20-Poly1305 AEAD to verify the Poly1305 tag.
     * Treat the entire message as AAD (sign-only). The AEAD tag is
     * produced/verified with the encryption key (no separate signing
     * key for AEAD policies). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_DecryptInit_ex(ctx, NULL, NULL,
                          cc->remoteSymEncryptingKey.data, maskedIv) != 1)
        goto errout;

    /* Set the expected tag for verification */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
                           UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH,
                           (void*)(uintptr_t)signature->data) != 1)
        goto errout;

    /* Process the entire message as AAD */
    int outl = 0;
    if(EVP_DecryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize triggers tag verification */
    UA_Byte dummy;
    if(EVP_DecryptFinal_ex(ctx, &dummy, &outl) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto errout;
    }
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

static UA_StatusCode
UA_SymSig_EccNistP256ChaChaPoly_sign(const UA_SecurityPolicy *policy,
                                 void *channelContext, const UA_ByteString *message,
                                 UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(signature->length < UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;

    /* Compute masked IV (same nonce derivation as encrypt mode) */
    UA_Byte maskedIv[12];
    computeMaskedIvChaChaPoly(maskedIv, &cc->localSymIv,
                          cc->tokenId, cc->previousSequenceNumber);

    /* Use ChaCha20-Poly1305 AEAD to compute the Poly1305 tag.
     * For sign-only: treat the entire message as AAD (no encryption).
     * The AEAD tag is produced with the encryption key (no separate
     * signing key for AEAD policies). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_EncryptInit_ex(ctx, NULL, NULL,
                          cc->localSymEncryptingKey.data, maskedIv) != 1)
        goto errout;

    /* Process the entire message as AAD (authenticated, not encrypted) */
    int outl = 0;
    if(EVP_EncryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize with no plaintext */
    UA_Byte dummy;
    if(EVP_EncryptFinal_ex(ctx, &dummy, &outl) != 1)
        goto errout;

    /* Get the 16-byte GCM authentication tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG,
                           UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH,
                           signature->data) != 1)
        goto errout;
    signature->length = UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH;
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

static size_t
UA_SymSig_EccNistP256ChaChaPoly_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_SYM_SIGNATURE_LENGTH;
}

/* --- Symmetric Encryption (ChaCha20-Poly1305 AEAD) --- */

static UA_StatusCode
UA_SymEn_EccNistP256ChaChaPoly_decrypt(const UA_SecurityPolicy *policy,
                                   void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;

    UA_Byte maskedIv[12];
    computeMaskedIvChaChaPoly(maskedIv, &cc->remoteSymIv,
                          cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_ChaCha20Poly1305_Decrypt(
        &ivBs, &cc->remoteSymEncryptingKey, &cc->additionalAuthData,
        data, true);
}

static UA_StatusCode
UA_SymEn_EccNistP256ChaChaPoly_encrypt(const UA_SecurityPolicy *policy,
                                   void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP256ChaChaPoly *cc =
        (Channel_Context_EccNistP256ChaChaPoly *)channelContext;

    UA_Byte maskedIv[12];
    computeMaskedIvChaChaPoly(maskedIv, &cc->localSymIv,
                          cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_ChaCha20Poly1305_Encrypt(
        &ivBs, &cc->localSymEncryptingKey, &cc->additionalAuthData,
        data, true);
}

static UA_StatusCode
EccNistP256ChaChaPoly_compareCertificate(const UA_SecurityPolicy *policy,
                                     const void *channelContext,
                                     const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccNistP256ChaChaPoly *cc =
        (const Channel_Context_EccNistP256ChaChaPoly *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_EccNistP256ChaChaPoly_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    /* No ECC encryption -> key length set to 1 to avoid division or
     * multiplication with 0 */
    return 1;
}

/* --- Public Entry Point --- */

UA_StatusCode
UA_SecurityPolicy_EccNistP256ChaChaPoly(UA_SecurityPolicy *sp,
                                    const UA_ApplicationType applicationType,
                                    const UA_ByteString localCertificate,
                                    const UA_ByteString localPrivateKey,
                                    const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_ChaChaPoly\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCNISTP256APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC_AEAD;

    /* Asymmetric Signature (ECDSA-SHA2-256).
     *
     * The URI here is what goes into the SignatureData.algorithm of the
     * CreateSession/ActivateSession signatures. For the ECC SecurityPolicies
     * the OPC UA reference stack (UA-.NETStandard) signs with an empty
     * algorithm but its verifier accepts EITHER an empty string OR the
     * SecurityPolicy URI (SecurityPolicies.cs, AsymmetricSignatureAlgorithm
     * EcdsaSha256: `IsNullOrEmpty(signature.Algorithm) || signature.Algorithm
     * == securityPolicy.Uri`). Empty is accepted by .NET/Softing but rejected
     * by stricter servers (e.g. CodeSys), so we send the SecurityPolicy URI -
     * the canonical non-empty value that interoperates with both. The
     * dedicated ECDSA URIs (xmldsig-more#ecdsa-sha256, conformanceunit/2473)
     * are NOT accepted and must not be used. */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_ChaChaPoly\0");
    asymSig->verify = UA_AsymSig_EccNistP256ChaChaPoly_verify;
    asymSig->sign = UA_AsymSig_EccNistP256ChaChaPoly_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccNistP256ChaChaPoly_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccNistP256ChaChaPoly_getRemoteSignatureSize;

    /* Asymmetric Encryption (none) */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccNistP256ChaChaPoly_Dummy;
    asymEnc->decrypt = UA_Asym_EccNistP256ChaChaPoly_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccNistP256ChaChaPoly_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccNistP256ChaChaPoly_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccNistP256ChaChaPoly_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccNistP256ChaChaPoly_getRemotePlainTextBlockSize;

    /* Symmetric Signature (ChaCha20-Poly1305, 16-byte tag) */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://opcfoundation.org/UA/security/chacha20-poly1305\0");
    symSig->verify = UA_SymSig_EccNistP256ChaChaPoly_verify;
    symSig->sign = UA_SymSig_EccNistP256ChaChaPoly_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccNistP256ChaChaPoly_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccNistP256ChaChaPoly_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccNistP256ChaChaPoly_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccNistP256ChaChaPoly_getRemoteKeyLength;

    /* Symmetric Encryption (ChaCha20-Poly1305 AEAD) */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://opcfoundation.org/UA/security/chacha20-poly1305\0");
    symEnc->encrypt = UA_SymEn_EccNistP256ChaChaPoly_encrypt;
    symEnc->decrypt = UA_SymEn_EccNistP256ChaChaPoly_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccNistP256ChaChaPoly_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccNistP256ChaChaPoly_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccNistP256ChaChaPoly_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccNistP256ChaChaPoly_getBlockSize;
    symEnc->getLocalIvLength = UA_SymEn_EccNistP256ChaChaPoly_getIvLength;

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = EccNistP256ChaChaPoly_New_Context;
    sp->deleteChannelContext = EccNistP256ChaChaPoly_Delete_Context;
    sp->setLocalSymEncryptingKey = EccNistP256ChaChaPoly_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccNistP256ChaChaPoly_setLocalSymSigningKey;
    sp->setLocalSymIv = EccNistP256ChaChaPoly_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccNistP256ChaChaPoly_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccNistP256ChaChaPoly_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccNistP256ChaChaPoly_setRemoteSymIv;
    sp->setMessageSecurityParameters = EccNistP256ChaChaPoly_setMessageSecurityParameters;
    sp->compareCertificate = EccNistP256ChaChaPoly_compareCertificate;
    sp->generateKey = UA_Sym_EccNistP256ChaChaPoly_generateKey;
    sp->generateNonce = UA_Sym_EccNistP256ChaChaPoly_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCNISTP256_CHACHAPOLY_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccNistP256ChaChaPoly;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccNistP256ChaChaPoly;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccNistP256ChaChaPoly;
    sp->createSigningRequest = createSigningRequest_sp_eccnistp256chachapoly;
    sp->clear = UA_Policy_EccNistP256ChaChaPoly_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_EC);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_EccNistP256ChaChaPoly_New_Context(sp, localPrivateKey,
                                                  applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_eccnistp384.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_SHA384_LENGTH 48 /* 384 bit */
#define UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNATURE_LENGTH 96
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP384_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCNISTP384_NONCE_LENGTH_BYTES 96

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccNistP384;

typedef struct Channel_Context_EccNistP384 {
    EVP_PKEY *    localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_EccNistP384;

static UA_StatusCode
UA_Policy_EccNistP384_New_Context(UA_SecurityPolicy *securityPolicy,
                                  const UA_ByteString localPrivateKey,
                                  const UA_ApplicationType applicationType,
                                  const UA_Logger *logger) {
    Policy_Context_EccNistP384 *context = (Policy_Context_EccNistP384 *)
        UA_malloc(sizeof(Policy_Context_EccNistP384));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccNistP384_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)policy->policyContext;
    if(!pc)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccnistp384(UA_SecurityPolicy *securityPolicy,
                                    const UA_String *subjectName,
                                    const UA_ByteString *nonce,
                                    const UA_KeyValueMap *params,
                                    UA_ByteString *csr,
                                    UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
     if(!securityPolicy->policyContext)
         return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384*)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccNistP384(UA_SecurityPolicy *securityPolicy,
                                              const UA_ByteString newCertificate,
                                              const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate,
        EVP_PKEY_EC);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccNistP384_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccNistP384_New_Context(const UA_SecurityPolicy *securityPolicy,
                        const UA_ByteString *remoteCertificate,
                        void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccNistP384 *newContext = (Channel_Context_EccNistP384 *)
        UA_calloc(1, sizeof(Channel_Context_EccNistP384));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&newContext->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    newContext->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&newContext->remoteCertificate, EVP_PKEY_EC);
    if(newContext->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&newContext->remoteCertificate);
        UA_free (newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = newContext;
    return UA_STATUSCODE_GOOD;
}

static void
EccNistP384_Delete_Context(const UA_SecurityPolicy *policy,
                           void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccNistP384 *cc =
        (Channel_Context_EccNistP384 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccNistP384(const UA_SecurityPolicy *policy,
                                            const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccNistP384(const UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString *certificate,
                                         UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static size_t
UA_Asym_EccNistP384_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccNistP384_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccNistP384_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP384_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccNistP384_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return 1;
}

static UA_StatusCode
UA_Sym_EccNistP384_generateNonce(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *out) {
    Policy_Context_EccNistP384* pctx = (Policy_Context_EccNistP384*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccNistP384 *cctx = (Channel_Context_EccNistP384*)channelContext;
        return UA_OpenSSL_ECC_NISTP384_GenerateKey(&cctx->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccNistP384_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                       const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccNistP384_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccNistP384_generateKey(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *secret,
                               const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccNistP384* pctx = (Policy_Context_EccNistP384 *)policy->policyContext;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_ECC_DeriveKeys(EC_curve_nist2nid("P-384"), "SHA384",
                                     pctx->applicationType, cc->localEphemeralKeyPair,
                                     secret, seed, out);
}

static UA_StatusCode
EccNistP384_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                  void *channelContext,
                                  const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccNistP384_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccNistP384_setLocalSymIv(const UA_SecurityPolicy *policy,
                          void *channelContext,
                          const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccNistP384_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccNistP384_getBlockSize(const UA_SecurityPolicy *policy,
                                  const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccNistP384_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                         const void *channelContext) {
    return UA_SECURITYPOLICY_ECCNISTP384_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccNistP384_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                   void *channelContext,
                                   const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccNistP384_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccNistP384_setRemoteSymIv(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccNistP384_sign(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccNistP384 *pc =
        (Policy_Context_EccNistP384 *)policy->policyContext;
    return UA_Openssl_ECDSA_SHA384_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymSig_EccNistP384_verify(const UA_SecurityPolicy *policy, void *channelContext,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_Openssl_ECDSA_SHA384_Verify(message, cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccNistP384_Dummy(const UA_SecurityPolicy *policy,
                          void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymSig_EccNistP384_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                             const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccNistP384_verify(const UA_SecurityPolicy *policy, void *channelContext,
                             const UA_ByteString *message, const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_OpenSSL_HMAC_SHA384_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccNistP384_sign(const UA_SecurityPolicy *policy,
                           void *channelContext, const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_OpenSSL_HMAC_SHA384_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccNistP384_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccNistP384_decrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_EccNistP384_encrypt(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccNistP384 *cc = (Channel_Context_EccNistP384 *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
EccNistP384_compareCertificate(const UA_SecurityPolicy *policy,
                               const void *channelContext,
                               const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccNistP384 *cc =
        (const Channel_Context_EccNistP384 *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_EccNistP384_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                        const void *channelContext) {
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccNistP384(UA_SecurityPolicy *sp,
                              const UA_ApplicationType applicationType,
                              const UA_ByteString localCertificate,
                              const UA_ByteString localPrivateKey,
                              const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_nistP384 is deprecated (OPC UA Part 7); "
                   "use ECC_nistP384_AesGcm or ECC_nistP384_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP384\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCNISTP384APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 15;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccNistP384_verify;
    asymSig->sign = UA_AsymSig_EccNistP384_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccNistP384_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccNistP384_getRemoteSignatureSize;

    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccNistP384_Dummy;
    asymEnc->decrypt = UA_Asym_EccNistP384_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccNistP384_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccNistP384_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccNistP384_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccNistP384_getRemotePlainTextBlockSize;

    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-384\0");
    symSig->verify = UA_SymSig_EccNistP384_verify;
    symSig->sign = UA_SymSig_EccNistP384_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccNistP384_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccNistP384_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccNistP384_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccNistP384_getRemoteKeyLength;

    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = UA_SymEn_EccNistP384_encrypt;
    symEnc->decrypt = UA_SymEn_EccNistP384_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccNistP384_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccNistP384_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccNistP384_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccNistP384_getBlockSize;

    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    sp->newChannelContext = EccNistP384_New_Context;
    sp->deleteChannelContext = EccNistP384_Delete_Context;
    sp->setLocalSymEncryptingKey = EccNistP384_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccNistP384_setLocalSymSigningKey;
    sp->setLocalSymIv = EccNistP384_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccNistP384_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccNistP384_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccNistP384_setRemoteSymIv;
    sp->compareCertificate = EccNistP384_compareCertificate;
    sp->generateKey = UA_Sym_EccNistP384_generateKey;
    sp->generateNonce = UA_Sym_EccNistP384_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCNISTP384_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccNistP384;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccNistP384;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccNistP384;
    sp->createSigningRequest = createSigningRequest_sp_eccnistp384;
    sp->clear = UA_Policy_EccNistP384_Clear_Context;

    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_EC);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = UA_Policy_EccNistP384_New_Context(sp, localPrivateKey, applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_eccbrainpoolp256r1.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNATURE_LENGTH 64
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_KEY_LENGTH 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_NONCE_LENGTH_BYTES 64

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccBrainpoolP256r1;

typedef struct Channel_Context_EccBrainpoolP256r1 {
    EVP_PKEY *    localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_EccBrainpoolP256r1;

static UA_StatusCode
UA_Policy_EccBrainpoolP256r1_New_Context(UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString localPrivateKey,
                                         const UA_ApplicationType applicationType,
                                         const UA_Logger *logger) {
    Policy_Context_EccBrainpoolP256r1 *context = (Policy_Context_EccBrainpoolP256r1 *)
        UA_malloc(sizeof(Policy_Context_EccBrainpoolP256r1));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccBrainpoolP256r1_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    if(!pc)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccbrainpoolp256r1(UA_SecurityPolicy *securityPolicy,
                                           const UA_String *subjectName,
                                           const UA_ByteString *nonce,
                                           const UA_KeyValueMap *params,
                                           UA_ByteString *csr,
                                           UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1*)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccBrainpoolP256r1(UA_SecurityPolicy *securityPolicy,
                                                     const UA_ByteString newCertificate,
                                                     const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate,
        EVP_PKEY_EC);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccBrainpoolP256r1_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccBrainpoolP256r1_New_Context(const UA_SecurityPolicy *securityPolicy,
                               const UA_ByteString *remoteCertificate,
                               void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccBrainpoolP256r1 *newContext = (Channel_Context_EccBrainpoolP256r1 *)
        UA_calloc(1, sizeof(Channel_Context_EccBrainpoolP256r1));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&newContext->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    newContext->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&newContext->remoteCertificate, EVP_PKEY_EC);
    if(newContext->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&newContext->remoteCertificate);
        UA_free (newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = newContext;
    return UA_STATUSCODE_GOOD;
}

static void
EccBrainpoolP256r1_Delete_Context(const UA_SecurityPolicy *policy,
                                  void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccBrainpoolP256r1(const UA_SecurityPolicy *policy,
                                                   const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccBrainpoolP256r1(const UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString *certificate,
                                                UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static size_t
UA_Asym_EccBrainpoolP256r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccBrainpoolP256r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                          const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP256r1_generateNonce(const UA_SecurityPolicy *policy,
                                        void *channelContext, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP256r1 *pctx =
        (Policy_Context_EccBrainpoolP256r1*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccBrainpoolP256r1 *cctx =
            (Channel_Context_EccBrainpoolP256r1*)channelContext;
        return UA_OpenSSL_ECC_BRAINPOOLP256R1_GenerateKey(&cctx->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccBrainpoolP256r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP256r1_generateKey(const UA_SecurityPolicy *policy,
                                      void *channelContext, const UA_ByteString *secret,
                                      const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP256r1 *pctx =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_ECC_DeriveKeys(OBJ_txt2nid("brainpoolP256r1"), "SHA256",
                                     pctx->applicationType, cc->localEphemeralKeyPair,
                                     secret, seed, out);
}

static UA_StatusCode
EccBrainpoolP256r1_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                            void *channelContext,
                                            const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setLocalSymIv(const UA_SecurityPolicy *policy,
                                 void *channelContext,
                                 const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccBrainpoolP256r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccBrainpoolP256r1_getBlockSize(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccBrainpoolP256r1_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                             void *channelContext,
                                             const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP256r1_setRemoteSymIv(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP256r1_sign(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP256r1 *pc =
        (Policy_Context_EccBrainpoolP256r1 *)policy->policyContext;
    return UA_Openssl_ECDSA_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP256r1_verify(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_Openssl_ECDSA_SHA256_Verify(message, cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccBrainpoolP256r1_Dummy(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP256r1_verify(const UA_SecurityPolicy *policy,
                                    void *channelContext,
                                    const UA_ByteString *message,
                                    const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP256r1_sign(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *message,
                                  UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccBrainpoolP256r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP256r1_decrypt(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP256r1_encrypt(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP256r1 *cc =
        (Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
EccBrainpoolP256r1_compareCertificate(const UA_SecurityPolicy *policy,
                                      const void *channelContext,
                                      const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccBrainpoolP256r1 *cc =
        (const Channel_Context_EccBrainpoolP256r1 *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_EccBrainpoolP256r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccBrainpoolP256r1(UA_SecurityPolicy *sp,
                                     const UA_ApplicationType applicationType,
                                     const UA_ByteString localCertificate,
                                     const UA_ByteString localPrivateKey,
                                     const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_brainpoolP256r1 is deprecated (OPC UA Part 7); "
                   "use ECC_brainpoolP256r1_AesGcm or ECC_brainpoolP256r1_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_brainpoolP256r1\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCBRAINPOOLP256R1APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccBrainpoolP256r1_verify;
    asymSig->sign = UA_AsymSig_EccBrainpoolP256r1_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccBrainpoolP256r1_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccBrainpoolP256r1_getRemoteSignatureSize;

    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccBrainpoolP256r1_Dummy;
    asymEnc->decrypt = UA_Asym_EccBrainpoolP256r1_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccBrainpoolP256r1_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccBrainpoolP256r1_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccBrainpoolP256r1_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccBrainpoolP256r1_getRemotePlainTextBlockSize;

    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSig->verify = UA_SymSig_EccBrainpoolP256r1_verify;
    symSig->sign = UA_SymSig_EccBrainpoolP256r1_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccBrainpoolP256r1_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccBrainpoolP256r1_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccBrainpoolP256r1_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccBrainpoolP256r1_getRemoteKeyLength;

    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEnc->encrypt = UA_SymEn_EccBrainpoolP256r1_encrypt;
    symEnc->decrypt = UA_SymEn_EccBrainpoolP256r1_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccBrainpoolP256r1_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccBrainpoolP256r1_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccBrainpoolP256r1_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccBrainpoolP256r1_getBlockSize;

    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    sp->newChannelContext = EccBrainpoolP256r1_New_Context;
    sp->deleteChannelContext = EccBrainpoolP256r1_Delete_Context;
    sp->setLocalSymEncryptingKey = EccBrainpoolP256r1_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccBrainpoolP256r1_setLocalSymSigningKey;
    sp->setLocalSymIv = EccBrainpoolP256r1_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccBrainpoolP256r1_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccBrainpoolP256r1_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccBrainpoolP256r1_setRemoteSymIv;
    sp->compareCertificate = EccBrainpoolP256r1_compareCertificate;
    sp->generateKey = UA_Sym_EccBrainpoolP256r1_generateKey;
    sp->generateNonce = UA_Sym_EccBrainpoolP256r1_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCBRAINPOOLP256R1_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccBrainpoolP256r1;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccBrainpoolP256r1;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccBrainpoolP256r1;
    sp->createSigningRequest = createSigningRequest_sp_eccbrainpoolp256r1;
    sp->clear = UA_Policy_EccBrainpoolP256r1_Clear_Context;

    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_EC);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = UA_Policy_EccBrainpoolP256r1_New_Context(sp, localPrivateKey,
                                                    applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_eccbrainpoolp384r1.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_SHA384_LENGTH 48 /* 384 bit */
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNATURE_LENGTH 96
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_SIGNING_KEY_LENGTH 48
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_NONCE_LENGTH_BYTES 96

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccBrainpoolP384r1;

typedef struct Channel_Context_EccBrainpoolP384r1 {
    EVP_PKEY *    localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_EccBrainpoolP384r1;

static UA_StatusCode
UA_Policy_EccBrainpoolP384r1_New_Context(UA_SecurityPolicy *securityPolicy,
                                         const UA_ByteString localPrivateKey,
                                         const UA_ApplicationType applicationType,
                                         const UA_Logger *logger) {
    Policy_Context_EccBrainpoolP384r1 *context = (Policy_Context_EccBrainpoolP384r1 *)
        UA_malloc(sizeof(Policy_Context_EccBrainpoolP384r1));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;

    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccBrainpoolP384r1_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    if(!pc)
        return;

    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_eccbrainpoolp384r1(UA_SecurityPolicy *securityPolicy,
                                           const UA_String *subjectName,
                                           const UA_ByteString *nonce,
                                           const UA_KeyValueMap *params,
                                           UA_ByteString *csr,
                                           UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1*)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccBrainpoolP384r1(UA_SecurityPolicy *securityPolicy,
                                                     const UA_ByteString newCertificate,
                                                     const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate,
        EVP_PKEY_EC);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccBrainpoolP384r1_Clear_Context(securityPolicy);
    return retval;
}

static UA_StatusCode
EccBrainpoolP384r1_New_Context(const UA_SecurityPolicy *securityPolicy,
                               const UA_ByteString *remoteCertificate,
                               void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccBrainpoolP384r1 *newContext = (Channel_Context_EccBrainpoolP384r1 *)
        UA_calloc(1, sizeof(Channel_Context_EccBrainpoolP384r1));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&newContext->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newContext);
        return retval;
    }

    newContext->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&newContext->remoteCertificate, EVP_PKEY_EC);
    if(newContext->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&newContext->remoteCertificate);
        UA_free (newContext);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = newContext;
    return UA_STATUSCODE_GOOD;
}

static void
EccBrainpoolP384r1_Delete_Context(const UA_SecurityPolicy *policy,
                                  void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccBrainpoolP384r1(const UA_SecurityPolicy *policy,
                                                   const UA_ByteString *certificateThumbprint) {
    if(policy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_makeCertificateThumbprint_EccBrainpoolP384r1(const UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString *certificate,
                                                UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static size_t
UA_Asym_EccBrainpoolP384r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsySig_EccBrainpoolP384r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                   const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                          const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return 1;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP384r1_generateNonce(const UA_SecurityPolicy *policy,
                                        void *channelContext, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP384r1 *pctx =
        (Policy_Context_EccBrainpoolP384r1*)policy->policyContext;
    if(!pctx)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccBrainpoolP384r1 *cctx =
            (Channel_Context_EccBrainpoolP384r1*)channelContext;
        return UA_OpenSSL_ECC_BRAINPOOLP384R1_GenerateKey(&cctx->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

static size_t
UA_SymEn_EccBrainpoolP384r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_EccBrainpoolP384r1_generateKey(const UA_SecurityPolicy *policy,
                                      void *channelContext, const UA_ByteString *secret,
                                      const UA_ByteString *seed, UA_ByteString *out) {
    Policy_Context_EccBrainpoolP384r1 *pctx =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_ECC_DeriveKeys(OBJ_txt2nid("brainpoolP384r1"), "SHA384",
                                     pctx->applicationType, cc->localEphemeralKeyPair,
                                     secret, seed, out);
}

static UA_StatusCode
EccBrainpoolP384r1_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                            void *channelContext,
                                            const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setLocalSymIv(const UA_SecurityPolicy *policy,
                                 void *channelContext,
                                 const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_EccBrainpoolP384r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccBrainpoolP384r1_getBlockSize(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    return UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
EccBrainpoolP384r1_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                             void *channelContext,
                                             const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccBrainpoolP384r1_setRemoteSymIv(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP384r1_sign(const UA_SecurityPolicy *policy,
                                   void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccBrainpoolP384r1 *pc =
        (Policy_Context_EccBrainpoolP384r1 *)policy->policyContext;
    return UA_Openssl_ECDSA_SHA384_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymSig_EccBrainpoolP384r1_verify(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_Openssl_ECDSA_SHA384_Verify(message, cc->remoteCertificateX509, signature);
}

static UA_StatusCode
UA_Asym_EccBrainpoolP384r1_Dummy(const UA_SecurityPolicy *policy,
                                 void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP384r1_verify(const UA_SecurityPolicy *policy,
                                    void *channelContext,
                                    const UA_ByteString *message,
                                    const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_OpenSSL_HMAC_SHA384_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_EccBrainpoolP384r1_sign(const UA_SecurityPolicy *policy,
                                  void *channelContext, const UA_ByteString *message,
                                  UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_OpenSSL_HMAC_SHA384_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_EccBrainpoolP384r1_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                    const void *channelContext) {
    return UA_SHA384_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP384r1_decrypt(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_EccBrainpoolP384r1_encrypt(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccBrainpoolP384r1 *cc =
        (Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
EccBrainpoolP384r1_compareCertificate(const UA_SecurityPolicy *policy,
                                      const void *channelContext,
                                      const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccBrainpoolP384r1 *cc =
        (const Channel_Context_EccBrainpoolP384r1 *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_EccBrainpoolP384r1_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return 1;
}

UA_StatusCode
UA_SecurityPolicy_EccBrainpoolP384r1(UA_SecurityPolicy *sp,
                                     const UA_ApplicationType applicationType,
                                     const UA_ByteString localCertificate,
                                     const UA_ByteString localPrivateKey,
                                     const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "SecurityPolicy ECC_brainpoolP384r1 is deprecated (OPC UA Part 7); "
                   "use ECC_brainpoolP384r1_AesGcm or ECC_brainpoolP384r1_ChaChaPoly instead");
    sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_brainpoolP384r1\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NS0ID(ECCBRAINPOOLP384R1APPLICATIONCERTIFICATETYPE);
    sp->securityLevel = 15;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC;

    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccBrainpoolP384r1_verify;
    asymSig->sign = UA_AsymSig_EccBrainpoolP384r1_sign;
    asymSig->getLocalSignatureSize = UA_AsySig_EccBrainpoolP384r1_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_Asym_EccBrainpoolP384r1_getRemoteSignatureSize;

    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccBrainpoolP384r1_Dummy;
    asymEnc->decrypt = UA_Asym_EccBrainpoolP384r1_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccBrainpoolP384r1_getLocalKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccBrainpoolP384r1_getRemoteKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccBrainpoolP384r1_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_EccBrainpoolP384r1_getRemotePlainTextBlockSize;

    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-384\0");
    symSig->verify = UA_SymSig_EccBrainpoolP384r1_verify;
    symSig->sign = UA_SymSig_EccBrainpoolP384r1_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccBrainpoolP384r1_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccBrainpoolP384r1_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccBrainpoolP384r1_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccBrainpoolP384r1_getRemoteKeyLength;

    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEnc->encrypt = UA_SymEn_EccBrainpoolP384r1_encrypt;
    symEnc->decrypt = UA_SymEn_EccBrainpoolP384r1_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccBrainpoolP384r1_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccBrainpoolP384r1_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccBrainpoolP384r1_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccBrainpoolP384r1_getBlockSize;

    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    sp->newChannelContext = EccBrainpoolP384r1_New_Context;
    sp->deleteChannelContext = EccBrainpoolP384r1_Delete_Context;
    sp->setLocalSymEncryptingKey = EccBrainpoolP384r1_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccBrainpoolP384r1_setLocalSymSigningKey;
    sp->setLocalSymIv = EccBrainpoolP384r1_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccBrainpoolP384r1_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccBrainpoolP384r1_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccBrainpoolP384r1_setRemoteSymIv;
    sp->compareCertificate = EccBrainpoolP384r1_compareCertificate;
    sp->generateKey = UA_Sym_EccBrainpoolP384r1_generateKey;
    sp->generateNonce = UA_Sym_EccBrainpoolP384r1_generateNonce;
    sp->nonceLength = UA_SECURITYPOLICY_ECCBRAINPOOLP384R1_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccBrainpoolP384r1;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccBrainpoolP384r1;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccBrainpoolP384r1;
    sp->createSigningRequest = createSigningRequest_sp_eccbrainpoolp384r1;
    sp->clear = UA_Policy_EccBrainpoolP384r1_Clear_Context;

    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                        EVP_PKEY_EC);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = UA_Policy_EccBrainpoolP384r1_New_Context(sp, localPrivateKey,
                                                    applicationType, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_ecccurve25519.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_ECCCURVE25519_ASYM_SIGNATURE_LENGTH 64
#define UA_ECCCURVE25519_SYM_SIGNING_KEY_LENGTH 32
#define UA_ECCCURVE25519_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_ECCCURVE25519_SYM_IV_LENGTH 12
#define UA_ECCCURVE25519_SYM_SIGNATURE_LENGTH 16  /* Poly1305 tag */
#define UA_ECCCURVE25519_NONCE_LENGTH_BYTES 32    /* X25519 public key */

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccCurve25519;

typedef struct {
    EVP_PKEY *localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509;

    /* AEAD message context (set before each encrypt/decrypt) */
    UA_UInt32 tokenId;
    UA_UInt32 previousSequenceNumber;
    UA_ByteString additionalAuthData;
} Channel_Context_EccCurve25519;

/* Compute the masked IV for ChaCha20-Poly1305.
 * iv_out must be 12 bytes. base_iv must be 12 bytes. */
static void
computeMaskedIv(UA_Byte *iv_out, const UA_ByteString *base_iv,
                UA_UInt32 tokenId, UA_UInt32 seqNo) {
    memcpy(iv_out, base_iv->data, 12);
    iv_out[0] ^= (UA_Byte)(tokenId & 0xFF);
    iv_out[1] ^= (UA_Byte)((tokenId >> 8) & 0xFF);
    iv_out[2] ^= (UA_Byte)((tokenId >> 16) & 0xFF);
    iv_out[3] ^= (UA_Byte)((tokenId >> 24) & 0xFF);
    iv_out[4] ^= (UA_Byte)(seqNo & 0xFF);
    iv_out[5] ^= (UA_Byte)((seqNo >> 8) & 0xFF);
    iv_out[6] ^= (UA_Byte)((seqNo >> 16) & 0xFF);
    iv_out[7] ^= (UA_Byte)((seqNo >> 24) & 0xFF);
}

/* --- Policy Context --- */

static UA_StatusCode
UA_Policy_EccCurve25519_New_Context(UA_SecurityPolicy *securityPolicy,
                                     const UA_ByteString localPrivateKey,
                                     const UA_ApplicationType applicationType,
                                     const UA_Logger *logger) {
    Policy_Context_EccCurve25519 *context = (Policy_Context_EccCurve25519 *)
        UA_malloc(sizeof(Policy_Context_EccCurve25519));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;
    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccCurve25519_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccCurve25519 *pc =
        (Policy_Context_EccCurve25519 *)policy->policyContext;
    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_ecccurve25519(UA_SecurityPolicy *securityPolicy,
                                      const UA_String *subjectName,
                                      const UA_ByteString *nonce,
                                      const UA_KeyValueMap *params,
                                      UA_ByteString *csr,
                                      UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccCurve25519 *pc =
        (Policy_Context_EccCurve25519 *)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccCurve25519(UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString newCertificate,
                                                 const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccCurve25519 *pc =
        (Policy_Context_EccCurve25519 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate, EVP_PKEY_ED25519);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccCurve25519_Clear_Context(securityPolicy);
    return retval;
}

/* --- Channel Context --- */

static UA_StatusCode
EccCurve25519_New_Context(const UA_SecurityPolicy *securityPolicy,
                          const UA_ByteString *remoteCertificate,
                          void **channelContext) {
    if(!securityPolicy || !remoteCertificate || !channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccCurve25519 *cc = (Channel_Context_EccCurve25519 *)
        UA_calloc(1, sizeof(Channel_Context_EccCurve25519));
    if(!cc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&cc->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(cc);
        return retval;
    }

    cc->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&cc->remoteCertificate, EVP_PKEY_ED25519);
    if(!cc->remoteCertificateX509) {
        UA_ByteString_clear(&cc->remoteCertificate);
        UA_free(cc);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = cc;
    return UA_STATUSCODE_GOOD;
}

static void
EccCurve25519_Delete_Context(const UA_SecurityPolicy *policy,
                             void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_ByteString_clear(&cc->additionalAuthData);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

/* --- AEAD Message Security Parameters --- */

static UA_StatusCode
EccCurve25519_setMessageSecurityParameters(const UA_SecurityPolicy *policy,
                                            void *channelContext,
                                            UA_UInt32 tokenId,
                                            UA_UInt32 previousSequenceNumber,
                                            const UA_ByteString *additionalAuthData) {
    if(!channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;
    cc->tokenId = tokenId;
    cc->previousSequenceNumber = previousSequenceNumber;

    /* Copy AAD */
    UA_ByteString_clear(&cc->additionalAuthData);
    if(additionalAuthData && additionalAuthData->length > 0)
        return UA_ByteString_copy(additionalAuthData, &cc->additionalAuthData);
    return UA_STATUSCODE_GOOD;
}

/* --- Asymmetric Signature (Ed25519) --- */

static UA_StatusCode
UA_AsymSig_EccCurve25519_sign(const UA_SecurityPolicy *policy,
                               void *channelContext, const UA_ByteString *message,
                               UA_ByteString *signature) {
    if(!channelContext || !message || !signature)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccCurve25519 *pc =
        (Policy_Context_EccCurve25519 *)policy->policyContext;
    return UA_OpenSSL_EdDSA_Ed25519_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymSig_EccCurve25519_verify(const UA_SecurityPolicy *policy,
                                 void *channelContext,
                                 const UA_ByteString *message,
                                 const UA_ByteString *signature) {
    if(!message || !signature || !channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;
    return UA_OpenSSL_EdDSA_Ed25519_Verify(message, cc->remoteCertificateX509,
                                            signature);
}

static size_t
UA_AsymSig_EccCurve25519_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return UA_ECCCURVE25519_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymSig_EccCurve25519_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                  const void *channelContext) {
    return UA_ECCCURVE25519_ASYM_SIGNATURE_LENGTH;
}

/* --- Asymmetric Encryption (dummy - ECC has no asymmetric encryption) --- */

static UA_StatusCode
UA_Asym_EccCurve25519_Dummy(const UA_SecurityPolicy *policy,
                             void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_AsymEn_EccCurve25519_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                     const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccCurve25519_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return 1;
}

static size_t
UA_AsymEn_EccCurve25519_getKeyLength(const UA_SecurityPolicy *policy,
                                      const void *channelContext) {
    return 1;
}

/* --- Symmetric Signature (Poly1305 for sign-only mode) --- */

static size_t
UA_SymSig_EccCurve25519_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                               const void *channelContext) {
    return UA_ECCCURVE25519_SYM_SIGNATURE_LENGTH;
}

static size_t
UA_SymSig_EccCurve25519_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                 const void *channelContext) {
    return UA_ECCCURVE25519_SYM_SIGNATURE_LENGTH;
}

static size_t
UA_SymSig_EccCurve25519_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_ECCCURVE25519_SYM_SIGNING_KEY_LENGTH;
}

static size_t
UA_SymSig_EccCurve25519_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                            const void *channelContext) {
    return UA_ECCCURVE25519_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccCurve25519_sign(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *message,
                              UA_ByteString *signature) {
    if(!channelContext || !message || !signature)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;

    /* Compute masked IV (same nonce derivation as encrypt mode) */
    UA_Byte maskedIv[12];
    computeMaskedIv(maskedIv, &cc->localSymIv,
                    cc->tokenId, cc->previousSequenceNumber);

    /* Use ChaCha20-Poly1305 AEAD to compute the Poly1305 tag.
     * For sign-only: treat entire message as AAD (no encryption). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_EncryptInit_ex(ctx, NULL, NULL,
                          cc->localSymSigningKey.data, maskedIv) != 1)
        goto errout;

    /* Process the entire message as AAD (authenticated, not encrypted) */
    int outl = 0;
    if(EVP_EncryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize with no plaintext */
    UA_Byte dummy;
    if(EVP_EncryptFinal_ex(ctx, &dummy, &outl) != 1)
        goto errout;

    /* Get the 16-byte Poly1305 authentication tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16,
                           signature->data) != 1)
        goto errout;
    signature->length = 16;
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

static UA_StatusCode
UA_SymSig_EccCurve25519_verify(const UA_SecurityPolicy *policy,
                                void *channelContext, const UA_ByteString *message,
                                const UA_ByteString *signature) {
    if(!channelContext || !message || !signature)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;

    if(signature->length < 16)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compute masked IV using remote IV */
    UA_Byte maskedIv[12];
    computeMaskedIv(maskedIv, &cc->remoteSymIv,
                    cc->tokenId, cc->previousSequenceNumber);

    /* Use ChaCha20-Poly1305 AEAD to verify the Poly1305 tag.
     * Treat entire message as AAD (sign-only). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_DecryptInit_ex(ctx, NULL, NULL,
                          cc->remoteSymSigningKey.data, maskedIv) != 1)
        goto errout;

    /* Set the expected tag for verification */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16,
                           (void*)(uintptr_t)signature->data) != 1)
        goto errout;

    /* Process the entire message as AAD */
    int outl = 0;
    if(EVP_DecryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize triggers tag verification */
    UA_Byte dummy;
    if(EVP_DecryptFinal_ex(ctx, &dummy, &outl) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto errout;
    }
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

/* --- Symmetric Encryption (ChaCha20-Poly1305 AEAD) --- */

static size_t
UA_SymEn_EccCurve25519_getLocalKeyLength(const UA_SecurityPolicy *policy,
                                          const void *channelContext) {
    return UA_ECCCURVE25519_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccCurve25519_getRemoteKeyLength(const UA_SecurityPolicy *policy,
                                           const void *channelContext) {
    return UA_ECCCURVE25519_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccCurve25519_getBlockSize(const UA_SecurityPolicy *policy,
                                     const void *channelContext) {
    return 1; /* No block alignment for AEAD */
}

static size_t
UA_SymEn_EccCurve25519_getIvLength(const UA_SecurityPolicy *policy,
                                    const void *channelContext) {
    return UA_ECCCURVE25519_SYM_IV_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccCurve25519_encrypt(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(!channelContext || !data)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;

    /* Compute masked IV */
    UA_Byte maskedIv[12];
    computeMaskedIv(maskedIv, &cc->localSymIv,
                    cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_ChaCha20Poly1305_Encrypt(
        &ivBs, &cc->localSymEncryptingKey, &cc->additionalAuthData,
        data, true /* encryptData */);
}

static UA_StatusCode
UA_SymEn_EccCurve25519_decrypt(const UA_SecurityPolicy *policy,
                                void *channelContext, UA_ByteString *data) {
    if(!channelContext || !data)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;

    /* Compute masked IV */
    UA_Byte maskedIv[12];
    computeMaskedIv(maskedIv, &cc->remoteSymIv,
                    cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_ChaCha20Poly1305_Decrypt(
        &ivBs, &cc->remoteSymEncryptingKey, &cc->additionalAuthData,
        data, true /* decryptData */);
}

/* --- Key Setters --- */

static UA_StatusCode
EccCurve25519_setLocalSymSigningKey(const UA_SecurityPolicy *policy,
                                     void *channelContext,
                                     const UA_ByteString *key) {
    if(!key || !channelContext) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc = (Channel_Context_EccCurve25519 *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccCurve25519_setLocalSymEncryptingKey(const UA_SecurityPolicy *policy,
                                        void *channelContext,
                                        const UA_ByteString *key) {
    if(!key || !channelContext) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc = (Channel_Context_EccCurve25519 *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccCurve25519_setLocalSymIv(const UA_SecurityPolicy *policy,
                             void *channelContext, const UA_ByteString *iv) {
    if(!iv || !channelContext) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc = (Channel_Context_EccCurve25519 *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
EccCurve25519_setRemoteSymSigningKey(const UA_SecurityPolicy *policy,
                                      void *channelContext,
                                      const UA_ByteString *key) {
    if(!key || !channelContext) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc = (Channel_Context_EccCurve25519 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccCurve25519_setRemoteSymEncryptingKey(const UA_SecurityPolicy *policy,
                                         void *channelContext,
                                         const UA_ByteString *key) {
    if(!key || !channelContext) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc = (Channel_Context_EccCurve25519 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccCurve25519_setRemoteSymIv(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *iv) {
    if(!iv || !channelContext) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve25519 *cc = (Channel_Context_EccCurve25519 *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

/* --- Compare Certificate --- */

static UA_StatusCode
EccCurve25519_compareCertificate(const UA_SecurityPolicy *policy,
                                  const void *channelContext,
                                  const UA_ByteString *certificate) {
    if(!channelContext || !certificate)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccCurve25519 *cc =
        (const Channel_Context_EccCurve25519 *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

/* --- Nonce Generation (X25519 ephemeral key) --- */

static UA_StatusCode
UA_Sym_EccCurve25519_generateNonce(const UA_SecurityPolicy *policy,
                                    void *channelContext, UA_ByteString *out) {
    if(!policy->policyContext)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Detect ephemeral key generation request */
    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccCurve25519 *cc =
            (Channel_Context_EccCurve25519 *)channelContext;
        return UA_OpenSSL_X25519_GenerateKey(&cc->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

/* --- Key Derivation (XDHE + HKDF) --- */

static UA_StatusCode
UA_Sym_EccCurve25519_generateKey(const UA_SecurityPolicy *policy,
                                  void *channelContext,
                                  const UA_ByteString *secret,
                                  const UA_ByteString *seed,
                                  UA_ByteString *out) {
    Policy_Context_EccCurve25519 *pctx =
        (Policy_Context_EccCurve25519 *)policy->policyContext;
    Channel_Context_EccCurve25519 *cc =
        (Channel_Context_EccCurve25519 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_XDHE_DeriveKeys(EVP_PKEY_X25519, "SHA256",
                                       pctx->applicationType,
                                       cc->localEphemeralKeyPair,
                                       secret, seed, out);
}

/* --- Thumbprint --- */

static UA_StatusCode
UA_makeCertificateThumbprint_EccCurve25519(const UA_SecurityPolicy *policy,
                                            const UA_ByteString *certificate,
                                            UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccCurve25519(const UA_SecurityPolicy *policy,
                                               const UA_ByteString *certificateThumbprint) {
    if(!policy || !certificateThumbprint)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccCurve25519 *pc =
        (Policy_Context_EccCurve25519 *)policy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

/* --- Public Entry Point --- */

UA_StatusCode
UA_SecurityPolicy_EccCurve25519(UA_SecurityPolicy *sp,
                                 const UA_ApplicationType applicationType,
                                 const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey,
                                 const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_curve25519\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NODEID_NUMERIC(0, 23542);
    sp->securityLevel = 10;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC_AEAD;

    /* Asymmetric Signature (Ed25519) */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccCurve25519_verify;
    asymSig->sign = UA_AsymSig_EccCurve25519_sign;
    asymSig->getLocalSignatureSize = UA_AsymSig_EccCurve25519_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_AsymSig_EccCurve25519_getRemoteSignatureSize;

    /* Asymmetric Encryption (dummy for ECC) */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri =
        UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccCurve25519_Dummy;
    asymEnc->decrypt = UA_Asym_EccCurve25519_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccCurve25519_getKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccCurve25519_getKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccCurve25519_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize =
        UA_AsymEn_EccCurve25519_getRemotePlainTextBlockSize;

    /* Symmetric Signature (Poly1305) */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri =
        UA_STRING("http://opcfoundation.org/UA/security/poly1305\0");
    symSig->verify = UA_SymSig_EccCurve25519_verify;
    symSig->sign = UA_SymSig_EccCurve25519_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccCurve25519_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccCurve25519_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccCurve25519_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccCurve25519_getRemoteKeyLength;

    /* Symmetric Encryption (ChaCha20-Poly1305 AEAD) */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri =
        UA_STRING("http://opcfoundation.org/UA/security/chacha20-poly1305\0");
    symEnc->encrypt = UA_SymEn_EccCurve25519_encrypt;
    symEnc->decrypt = UA_SymEn_EccCurve25519_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccCurve25519_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccCurve25519_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccCurve25519_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccCurve25519_getBlockSize;
    symEnc->getLocalIvLength = UA_SymEn_EccCurve25519_getIvLength;

    /* Certificate signing uses the same algorithm as asymmetric */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = EccCurve25519_New_Context;
    sp->deleteChannelContext = EccCurve25519_Delete_Context;
    sp->setLocalSymEncryptingKey = EccCurve25519_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccCurve25519_setLocalSymSigningKey;
    sp->setLocalSymIv = EccCurve25519_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccCurve25519_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccCurve25519_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccCurve25519_setRemoteSymIv;
    sp->setMessageSecurityParameters = EccCurve25519_setMessageSecurityParameters;
    sp->compareCertificate = EccCurve25519_compareCertificate;
    sp->generateKey = UA_Sym_EccCurve25519_generateKey;
    sp->generateNonce = UA_Sym_EccCurve25519_generateNonce;
    sp->nonceLength = UA_ECCCURVE25519_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccCurve25519;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccCurve25519;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccCurve25519;
    sp->createSigningRequest = createSigningRequest_sp_ecccurve25519;
    sp->clear = UA_Policy_EccCurve25519_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                         EVP_PKEY_ED25519);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_EccCurve25519_New_Context(sp, localPrivateKey, applicationType,
                                               logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_ecccurve448.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)

#include <openssl/rand.h>

#define UA_ECCCURVE448_ASYM_SIGNATURE_LENGTH 114
#define UA_ECCCURVE448_SYM_SIGNING_KEY_LENGTH 32
#define UA_ECCCURVE448_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_ECCCURVE448_SYM_IV_LENGTH 12
#define UA_ECCCURVE448_SYM_SIGNATURE_LENGTH 16  /* Poly1305 tag */
#define UA_ECCCURVE448_NONCE_LENGTH_BYTES 56    /* X448 public key */

typedef struct {
    EVP_PKEY *localPrivateKey;
    EVP_PKEY *csrLocalPrivateKey;
    UA_ByteString localCertThumbprint;
    UA_ApplicationType applicationType;
} Policy_Context_EccCurve448;

typedef struct {
    EVP_PKEY *localEphemeralKeyPair;
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509;

    /* AEAD message context */
    UA_UInt32 tokenId;
    UA_UInt32 previousSequenceNumber;
    UA_ByteString additionalAuthData;
} Channel_Context_EccCurve448;

static void
computeMaskedIv448(UA_Byte *iv_out, const UA_ByteString *base_iv,
                   UA_UInt32 tokenId, UA_UInt32 seqNo) {
    memcpy(iv_out, base_iv->data, 12);
    iv_out[0] ^= (UA_Byte)(tokenId & 0xFF);
    iv_out[1] ^= (UA_Byte)((tokenId >> 8) & 0xFF);
    iv_out[2] ^= (UA_Byte)((tokenId >> 16) & 0xFF);
    iv_out[3] ^= (UA_Byte)((tokenId >> 24) & 0xFF);
    iv_out[4] ^= (UA_Byte)(seqNo & 0xFF);
    iv_out[5] ^= (UA_Byte)((seqNo >> 8) & 0xFF);
    iv_out[6] ^= (UA_Byte)((seqNo >> 16) & 0xFF);
    iv_out[7] ^= (UA_Byte)((seqNo >> 24) & 0xFF);
}

/* --- Policy Context --- */

static UA_StatusCode
UA_Policy_EccCurve448_New_Context(UA_SecurityPolicy *securityPolicy,
                                   const UA_ByteString localPrivateKey,
                                   const UA_ApplicationType applicationType,
                                   const UA_Logger *logger) {
    Policy_Context_EccCurve448 *context = (Policy_Context_EccCurve448 *)
        UA_malloc(sizeof(Policy_Context_EccCurve448));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    context->csrLocalPrivateKey = NULL;

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->applicationType = applicationType;
    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_EccCurve448_Clear_Context(UA_SecurityPolicy *policy) {
    if(!policy || !policy->policyContext)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_EccCurve448 *pc =
        (Policy_Context_EccCurve448 *)policy->policyContext;
    EVP_PKEY_free(pc->localPrivateKey);
    EVP_PKEY_free(pc->csrLocalPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
}

static UA_StatusCode
createSigningRequest_sp_ecccurve448(UA_SecurityPolicy *securityPolicy,
                                    const UA_String *subjectName,
                                    const UA_ByteString *nonce,
                                    const UA_KeyValueMap *params,
                                    UA_ByteString *csr,
                                    UA_ByteString *newPrivateKey) {
    if(!securityPolicy || !csr)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccCurve448 *pc =
        (Policy_Context_EccCurve448 *)securityPolicy->policyContext;
    return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey,
                                           &pc->csrLocalPrivateKey,
                                           securityPolicy, subjectName,
                                           nonce, csr, newPrivateKey);
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_EccCurve448(UA_SecurityPolicy *securityPolicy,
                                               const UA_ByteString newCertificate,
                                               const UA_ByteString newPrivateKey) {
    if(!securityPolicy || !securityPolicy->policyContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_EccCurve448 *pc =
        (Policy_Context_EccCurve448 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);
    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate, EVP_PKEY_ED448);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    EVP_PKEY_free(pc->localPrivateKey);
    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);
    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext)
        UA_Policy_EccCurve448_Clear_Context(securityPolicy);
    return retval;
}

/* --- Channel Context --- */

static UA_StatusCode
EccCurve448_New_Context(const UA_SecurityPolicy *securityPolicy,
                        const UA_ByteString *remoteCertificate,
                        void **channelContext) {
    if(!securityPolicy || !remoteCertificate || !channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_EccCurve448 *cc = (Channel_Context_EccCurve448 *)
        UA_calloc(1, sizeof(Channel_Context_EccCurve448));
    if(!cc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_copyCertificate(&cc->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(cc);
        return retval;
    }

    cc->remoteCertificateX509 =
        UA_OpenSSL_LoadCertificate(&cc->remoteCertificate, EVP_PKEY_ED448);
    if(!cc->remoteCertificateX509) {
        UA_ByteString_clear(&cc->remoteCertificate);
        UA_free(cc);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    *channelContext = cc;
    return UA_STATUSCODE_GOOD;
}

static void
EccCurve448_Delete_Context(const UA_SecurityPolicy *policy,
                           void *channelContext) {
    if(!channelContext)
        return;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    UA_ByteString_clear(&cc->additionalAuthData);
    EVP_PKEY_free(cc->localEphemeralKeyPair);
    UA_free(cc);
}

/* --- AEAD Message Security Parameters --- */

static UA_StatusCode
EccCurve448_setMessageSecurityParameters(const UA_SecurityPolicy *policy,
                                          void *channelContext,
                                          UA_UInt32 tokenId,
                                          UA_UInt32 previousSequenceNumber,
                                          const UA_ByteString *additionalAuthData) {
    if(!channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;
    cc->tokenId = tokenId;
    cc->previousSequenceNumber = previousSequenceNumber;

    UA_ByteString_clear(&cc->additionalAuthData);
    if(additionalAuthData && additionalAuthData->length > 0)
        return UA_ByteString_copy(additionalAuthData, &cc->additionalAuthData);
    return UA_STATUSCODE_GOOD;
}

/* --- Asymmetric Signature (Ed448) --- */

static UA_StatusCode
UA_AsymSig_EccCurve448_sign(const UA_SecurityPolicy *policy,
                             void *channelContext, const UA_ByteString *message,
                             UA_ByteString *signature) {
    if(!channelContext || !message || !signature)
        return UA_STATUSCODE_BADINTERNALERROR;
    Policy_Context_EccCurve448 *pc =
        (Policy_Context_EccCurve448 *)policy->policyContext;
    return UA_OpenSSL_EdDSA_Ed448_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymSig_EccCurve448_verify(const UA_SecurityPolicy *policy,
                               void *channelContext,
                               const UA_ByteString *message,
                               const UA_ByteString *signature) {
    if(!message || !signature || !channelContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;
    return UA_OpenSSL_EdDSA_Ed448_Verify(message, cc->remoteCertificateX509,
                                          signature);
}

static size_t
UA_AsymSig_EccCurve448_getLocalSignatureSize(const UA_SecurityPolicy *policy,
                                              const void *channelContext) {
    return UA_ECCCURVE448_ASYM_SIGNATURE_LENGTH;
}

static size_t
UA_AsymSig_EccCurve448_getRemoteSignatureSize(const UA_SecurityPolicy *policy,
                                                const void *channelContext) {
    return UA_ECCCURVE448_ASYM_SIGNATURE_LENGTH;
}

/* --- Asymmetric Encryption (dummy) --- */

static UA_StatusCode
UA_Asym_EccCurve448_Dummy(const UA_SecurityPolicy *policy,
                           void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_AsymEn_EccCurve448_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy,
                                                   const void *ctx) {
    return 1;
}

static size_t
UA_AsymEn_EccCurve448_getRemoteBlockSize(const UA_SecurityPolicy *policy,
                                          const void *ctx) {
    return 1;
}

static size_t
UA_AsymEn_EccCurve448_getKeyLength(const UA_SecurityPolicy *policy,
                                    const void *ctx) {
    return 1;
}

/* --- Symmetric Signature (Poly1305) --- */

static size_t
UA_SymSig_EccCurve448_getLocalSignatureSize(const UA_SecurityPolicy *p,
                                             const void *ctx) {
    return UA_ECCCURVE448_SYM_SIGNATURE_LENGTH;
}

static size_t
UA_SymSig_EccCurve448_getRemoteSignatureSize(const UA_SecurityPolicy *p,
                                               const void *ctx) {
    return UA_ECCCURVE448_SYM_SIGNATURE_LENGTH;
}

static size_t
UA_SymSig_EccCurve448_getLocalKeyLength(const UA_SecurityPolicy *p,
                                         const void *ctx) {
    return UA_ECCCURVE448_SYM_SIGNING_KEY_LENGTH;
}

static size_t
UA_SymSig_EccCurve448_getRemoteKeyLength(const UA_SecurityPolicy *p,
                                          const void *ctx) {
    return UA_ECCCURVE448_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_SymSig_EccCurve448_sign(const UA_SecurityPolicy *policy,
                            void *channelContext, const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(!channelContext || !message || !signature)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;

    /* Compute masked IV (same nonce derivation as encrypt mode) */
    UA_Byte maskedIv[12];
    computeMaskedIv448(maskedIv, &cc->localSymIv,
                       cc->tokenId, cc->previousSequenceNumber);

    /* Use ChaCha20-Poly1305 AEAD to compute the Poly1305 tag.
     * For sign-only: treat entire message as AAD (no encryption). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_EncryptInit_ex(ctx, NULL, NULL,
                          cc->localSymSigningKey.data, maskedIv) != 1)
        goto errout;

    /* Process the entire message as AAD (authenticated, not encrypted) */
    int outl = 0;
    if(EVP_EncryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize with no plaintext */
    UA_Byte dummy;
    if(EVP_EncryptFinal_ex(ctx, &dummy, &outl) != 1)
        goto errout;

    /* Get the 16-byte Poly1305 authentication tag */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16,
                           signature->data) != 1)
        goto errout;
    signature->length = 16;
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

static UA_StatusCode
UA_SymSig_EccCurve448_verify(const UA_SecurityPolicy *policy,
                              void *channelContext, const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(!channelContext || !message || !signature)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;

    if(signature->length < 16)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compute masked IV using remote IV */
    UA_Byte maskedIv[12];
    computeMaskedIv448(maskedIv, &cc->remoteSymIv,
                       cc->tokenId, cc->previousSequenceNumber);

    /* Use ChaCha20-Poly1305 AEAD to verify the Poly1305 tag.
     * Treat entire message as AAD (sign-only). */
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_BADINTERNALERROR;
    if(EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, NULL, NULL) != 1)
        goto errout;
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, NULL) != 1)
        goto errout;
    if(EVP_DecryptInit_ex(ctx, NULL, NULL,
                          cc->remoteSymSigningKey.data, maskedIv) != 1)
        goto errout;

    /* Set the expected tag for verification */
    if(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16,
                           (void*)(uintptr_t)signature->data) != 1)
        goto errout;

    /* Process the entire message as AAD */
    int outl = 0;
    if(EVP_DecryptUpdate(ctx, NULL, &outl,
                         message->data, (int)message->length) != 1)
        goto errout;

    /* Finalize triggers tag verification */
    UA_Byte dummy;
    if(EVP_DecryptFinal_ex(ctx, &dummy, &outl) != 1) {
        ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto errout;
    }
    ret = UA_STATUSCODE_GOOD;

errout:
    EVP_CIPHER_CTX_free(ctx);
    return ret;
}

/* --- Symmetric Encryption (ChaCha20-Poly1305 AEAD) --- */

static size_t
UA_SymEn_EccCurve448_getLocalKeyLength(const UA_SecurityPolicy *p,
                                        const void *ctx) {
    return UA_ECCCURVE448_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccCurve448_getRemoteKeyLength(const UA_SecurityPolicy *p,
                                         const void *ctx) {
    return UA_ECCCURVE448_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_EccCurve448_getBlockSize(const UA_SecurityPolicy *p,
                                   const void *ctx) {
    return 1;
}

static size_t
UA_SymEn_EccCurve448_getIvLength(const UA_SecurityPolicy *p,
                                  const void *ctx) {
    return UA_ECCCURVE448_SYM_IV_LENGTH;
}

static UA_StatusCode
UA_SymEn_EccCurve448_encrypt(const UA_SecurityPolicy *policy,
                              void *channelContext, UA_ByteString *data) {
    if(!channelContext || !data)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;

    UA_Byte maskedIv[12];
    computeMaskedIv448(maskedIv, &cc->localSymIv,
                       cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_ChaCha20Poly1305_Encrypt(
        &ivBs, &cc->localSymEncryptingKey, &cc->additionalAuthData,
        data, true);
}

static UA_StatusCode
UA_SymEn_EccCurve448_decrypt(const UA_SecurityPolicy *policy,
                              void *channelContext, UA_ByteString *data) {
    if(!channelContext || !data)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;

    UA_Byte maskedIv[12];
    computeMaskedIv448(maskedIv, &cc->remoteSymIv,
                       cc->tokenId, cc->previousSequenceNumber);
    UA_ByteString ivBs = {12, maskedIv};

    return UA_OpenSSL_ChaCha20Poly1305_Decrypt(
        &ivBs, &cc->remoteSymEncryptingKey, &cc->additionalAuthData,
        data, true);
}

/* --- Key Setters --- */

static UA_StatusCode
EccCurve448_setLocalSymSigningKey(const UA_SecurityPolicy *p,
                                   void *ctx, const UA_ByteString *key) {
    if(!key || !ctx) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc = (Channel_Context_EccCurve448 *)ctx;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
EccCurve448_setLocalSymEncryptingKey(const UA_SecurityPolicy *p,
                                      void *ctx, const UA_ByteString *key) {
    if(!key || !ctx) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc = (Channel_Context_EccCurve448 *)ctx;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
EccCurve448_setLocalSymIv(const UA_SecurityPolicy *p,
                           void *ctx, const UA_ByteString *iv) {
    if(!iv || !ctx) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc = (Channel_Context_EccCurve448 *)ctx;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
EccCurve448_setRemoteSymSigningKey(const UA_SecurityPolicy *p,
                                    void *ctx, const UA_ByteString *key) {
    if(!key || !ctx) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc = (Channel_Context_EccCurve448 *)ctx;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
EccCurve448_setRemoteSymEncryptingKey(const UA_SecurityPolicy *p,
                                       void *ctx, const UA_ByteString *key) {
    if(!key || !ctx) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc = (Channel_Context_EccCurve448 *)ctx;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
EccCurve448_setRemoteSymIv(const UA_SecurityPolicy *p,
                            void *ctx, const UA_ByteString *iv) {
    if(!iv || !ctx) return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_EccCurve448 *cc = (Channel_Context_EccCurve448 *)ctx;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

/* --- Compare Certificate --- */

static UA_StatusCode
EccCurve448_compareCertificate(const UA_SecurityPolicy *policy,
                                const void *channelContext,
                                const UA_ByteString *certificate) {
    if(!channelContext || !certificate)
        return UA_STATUSCODE_BADINTERNALERROR;
    const Channel_Context_EccCurve448 *cc =
        (const Channel_Context_EccCurve448 *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

/* --- Nonce Generation (X448 ephemeral key) --- */

static UA_StatusCode
UA_Sym_EccCurve448_generateNonce(const UA_SecurityPolicy *policy,
                                  void *channelContext, UA_ByteString *out) {
    if(!policy->policyContext)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    if(out->data[0] == 'e' && out->data[1] == 'p' && out->data[2] == 'h') {
        Channel_Context_EccCurve448 *cc =
            (Channel_Context_EccCurve448 *)channelContext;
        return UA_OpenSSL_X448_GenerateKey(&cc->localEphemeralKeyPair, out);
    }

    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    return (rc == 1) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADUNEXPECTEDERROR;
}

/* --- Key Derivation (XDHE + HKDF) --- */

static UA_StatusCode
UA_Sym_EccCurve448_generateKey(const UA_SecurityPolicy *policy,
                                void *channelContext,
                                const UA_ByteString *secret,
                                const UA_ByteString *seed,
                                UA_ByteString *out) {
    Policy_Context_EccCurve448 *pctx =
        (Policy_Context_EccCurve448 *)policy->policyContext;
    Channel_Context_EccCurve448 *cc =
        (Channel_Context_EccCurve448 *)channelContext;
    if(!pctx || !cc)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_OpenSSL_XDHE_DeriveKeys(EVP_PKEY_X448, "SHA256",
                                       pctx->applicationType,
                                       cc->localEphemeralKeyPair,
                                       secret, seed, out);
}

/* --- Thumbprint --- */

static UA_StatusCode
UA_makeCertificateThumbprint_EccCurve448(const UA_SecurityPolicy *policy,
                                          const UA_ByteString *certificate,
                                          UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_compareCertificateThumbprint_EccCurve448(const UA_SecurityPolicy *policy,
                                             const UA_ByteString *certThumb) {
    if(!policy || !certThumb)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_EccCurve448 *pc =
        (Policy_Context_EccCurve448 *)policy->policyContext;
    if(!UA_ByteString_equal(certThumb, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

/* --- Public Entry Point --- */

UA_StatusCode
UA_SecurityPolicy_EccCurve448(UA_SecurityPolicy *sp,
                               const UA_ApplicationType applicationType,
                               const UA_ByteString localCertificate,
                               const UA_ByteString localPrivateKey,
                               const UA_Logger *logger) {
    memset(sp, 0, sizeof(UA_SecurityPolicy));
    sp->logger = logger;
    sp->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_curve448\0");
    sp->certificateGroupId =
        UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
    sp->certificateTypeId = UA_NODEID_NUMERIC(0, 23543);
    sp->securityLevel = 15;
    sp->policyType = UA_SECURITYPOLICYTYPE_ECC_AEAD;

    /* Asymmetric Signature (Ed448) */
    UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm;
    asymSig->uri = UA_STRING_NULL;
    asymSig->verify = UA_AsymSig_EccCurve448_verify;
    asymSig->sign = UA_AsymSig_EccCurve448_sign;
    asymSig->getLocalSignatureSize = UA_AsymSig_EccCurve448_getLocalSignatureSize;
    asymSig->getRemoteSignatureSize = UA_AsymSig_EccCurve448_getRemoteSignatureSize;

    /* Asymmetric Encryption (dummy) */
    UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm;
    asymEnc->uri =
        UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
    asymEnc->encrypt = UA_Asym_EccCurve448_Dummy;
    asymEnc->decrypt = UA_Asym_EccCurve448_Dummy;
    asymEnc->getLocalKeyLength = UA_AsymEn_EccCurve448_getKeyLength;
    asymEnc->getRemoteKeyLength = UA_AsymEn_EccCurve448_getKeyLength;
    asymEnc->getRemoteBlockSize = UA_AsymEn_EccCurve448_getRemoteBlockSize;
    asymEnc->getRemotePlainTextBlockSize =
        UA_AsymEn_EccCurve448_getRemotePlainTextBlockSize;

    /* Symmetric Signature (Poly1305) */
    UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm;
    symSig->uri =
        UA_STRING("http://opcfoundation.org/UA/security/poly1305\0");
    symSig->verify = UA_SymSig_EccCurve448_verify;
    symSig->sign = UA_SymSig_EccCurve448_sign;
    symSig->getLocalSignatureSize = UA_SymSig_EccCurve448_getLocalSignatureSize;
    symSig->getRemoteSignatureSize = UA_SymSig_EccCurve448_getRemoteSignatureSize;
    symSig->getLocalKeyLength = UA_SymSig_EccCurve448_getLocalKeyLength;
    symSig->getRemoteKeyLength = UA_SymSig_EccCurve448_getRemoteKeyLength;

    /* Symmetric Encryption (ChaCha20-Poly1305 AEAD) */
    UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm;
    symEnc->uri =
        UA_STRING("http://opcfoundation.org/UA/security/chacha20-poly1305\0");
    symEnc->encrypt = UA_SymEn_EccCurve448_encrypt;
    symEnc->decrypt = UA_SymEn_EccCurve448_decrypt;
    symEnc->getLocalKeyLength = UA_SymEn_EccCurve448_getLocalKeyLength;
    symEnc->getRemoteKeyLength = UA_SymEn_EccCurve448_getRemoteKeyLength;
    symEnc->getRemoteBlockSize = UA_SymEn_EccCurve448_getBlockSize;
    symEnc->getRemotePlainTextBlockSize = UA_SymEn_EccCurve448_getBlockSize;
    symEnc->getLocalIvLength = UA_SymEn_EccCurve448_getIvLength;

    /* Certificate signing uses the same algorithm as asymmetric */
    sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm;

    /* Direct Method Pointers */
    sp->newChannelContext = EccCurve448_New_Context;
    sp->deleteChannelContext = EccCurve448_Delete_Context;
    sp->setLocalSymEncryptingKey = EccCurve448_setLocalSymEncryptingKey;
    sp->setLocalSymSigningKey = EccCurve448_setLocalSymSigningKey;
    sp->setLocalSymIv = EccCurve448_setLocalSymIv;
    sp->setRemoteSymEncryptingKey = EccCurve448_setRemoteSymEncryptingKey;
    sp->setRemoteSymSigningKey = EccCurve448_setRemoteSymSigningKey;
    sp->setRemoteSymIv = EccCurve448_setRemoteSymIv;
    sp->setMessageSecurityParameters = EccCurve448_setMessageSecurityParameters;
    sp->compareCertificate = EccCurve448_compareCertificate;
    sp->generateKey = UA_Sym_EccCurve448_generateKey;
    sp->generateNonce = UA_Sym_EccCurve448_generateNonce;
    sp->nonceLength = UA_ECCCURVE448_NONCE_LENGTH_BYTES;
    sp->makeCertThumbprint = UA_makeCertificateThumbprint_EccCurve448;
    sp->compareCertThumbprint = UA_compareCertificateThumbprint_EccCurve448;
    sp->updateCertificate = updateCertificateAndPrivateKey_sp_EccCurve448;
    sp->createSigningRequest = createSigningRequest_sp_ecccurve448;
    sp->clear = UA_Policy_EccCurve448_Clear_Context;

    /* Parse the certificate */
    UA_Openssl_Init();
    UA_StatusCode res =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate,
                                         EVP_PKEY_ED448);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Create the policy context */
    res = UA_Policy_EccCurve448_New_Context(sp, localPrivateKey, applicationType,
                                             logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&sp->localCertificate);
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/create_certificate.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2022 (c) Wind River Systems, Inc.
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
 *
 */



#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)

#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>

/**
 * Join an array of UA_String to a single NULL-Terminated UA_String
 * separated by character sep
 */
static UA_StatusCode
join_string_with_sep(const UA_String *strings, size_t stringsSize,
                     char sep, UA_String *out) {
    if(!out)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_String_clear(out);
    size_t totalSize = stringsSize;
    for(size_t iStr = 0; iStr < stringsSize; ++iStr) {
        totalSize += strings[iStr].length;
    }

    UA_ByteString_allocBuffer(out, totalSize);
    if(!out->data) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    size_t pos = 0;
    for(size_t iStr = 0; iStr < stringsSize; ++iStr) {
        memcpy(&out->data[pos], strings[iStr].data, strings[iStr].length);
        pos += strings[iStr].length;
        out->data[pos] = (UA_Byte) sep;
        ++pos;
    }
    out->data[out->length-1] = 0;

    return UA_STATUSCODE_GOOD;
}

/**
 * Search for a character in a string (like strchr).
 * \todo Handle UTF-8
 *
 * \return index of the character or -1 on case of an error.
 */

static UA_Int32
UA_String_chr(const UA_String *pUaStr, char needl) {
    UA_Byte byteNeedl = (UA_Byte)needl;
    for(size_t i = 0; (size_t)i < pUaStr->length; ++i) {
        if(pUaStr->data[i] == byteNeedl) {
            return (UA_Int32) i;
        }
    }
    return -1;
}

/* char *value cannot be const due to openssl 1.0 compatibility */
static UA_StatusCode
add_x509V3ext(const UA_Logger *logger, X509 *x509, int nid, char *value) {
    X509_EXTENSION *ex;
    X509V3_CTX ctx;
    X509V3_set_ctx_nodb(&ctx);
    X509V3_set_ctx(&ctx, x509, x509, NULL, NULL, 0);
    ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
    if(!ex)
    {
#if UA_LOGLEVEL <= 300
        const char * file =  NULL;
        int line =  0;
        const char * data =  NULL;
        int flags =  0;
        get_error_line_data(&file, &line, &data, &flags);
        UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Internal SSL error file: %s:%d data: %s", file, line, data);
#endif
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    X509_add_ext(x509, ex, -1);
    X509_EXTENSION_free(ex);
    return UA_STATUSCODE_GOOD;
}

/* Check if a UA_String equals a C string literal (case-insensitive) */
static UA_Boolean
uaStringEqualsCI(const UA_String *uaStr, const char *cStr) {
    size_t cLen = strlen(cStr);
    if(uaStr->length != cLen)
        return false;
    for(size_t i = 0; i < cLen; i++) {
        char a = (char)uaStr->data[i];
        char b = cStr[i];
        if(a >= 'A' && a <= 'Z') a = (char)(a + 32);
        if(b >= 'A' && b <= 'Z') b = (char)(b + 32);
        if(a != b) return false;
    }
    return true;
}

#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)

/* generate the RSA key */

static EVP_PKEY * UA_RSA_Generate_Key (size_t keySizeBits){
    return EVP_RSA_gen(keySizeBits);
}

/* Generate an ECC key for the given curve name.
 * Returns NULL on failure. */
static EVP_PKEY *
UA_ECC_Generate_Key(const UA_Logger *logger, const UA_String *curveName) {
    /* EdDSA curves use a different keygen path */
    if(uaStringEqualsCI(curveName, "ed25519"))
        return EVP_PKEY_Q_keygen(NULL, NULL, "ED25519");
    if(uaStringEqualsCI(curveName, "ed448"))
        return EVP_PKEY_Q_keygen(NULL, NULL, "ED448");

    /* ECDSA curves: map name to OpenSSL curve name */
    const char *osslCurve = NULL;
    if(uaStringEqualsCI(curveName, "prime256v1") ||
       uaStringEqualsCI(curveName, "nistp256"))
        osslCurve = "prime256v1";
    else if(uaStringEqualsCI(curveName, "secp384r1") ||
            uaStringEqualsCI(curveName, "nistp384"))
        osslCurve = "secp384r1";
    else if(uaStringEqualsCI(curveName, "brainpoolp256r1"))
        osslCurve = "brainpoolP256r1";
    else if(uaStringEqualsCI(curveName, "brainpoolp384r1"))
        osslCurve = "brainpoolP384r1";

    if(!osslCurve) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Unsupported ECC curve.");
        return NULL;
    }

    return EVP_EC_gen(osslCurve);
}

#endif

UA_StatusCode
UA_CreateCertificate(const UA_Logger *logger, const UA_String *subject,
                     size_t subjectSize, const UA_String *subjectAltName,
                     size_t subjectAltNameSize, UA_CertificateFormat certFormat,
                     UA_KeyValueMap *params, UA_ByteString *outPrivateKey,
                     UA_ByteString *outCertificate) {
    if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || !subject ||
       subjectAltNameSize == 0 || subjectSize == 0 ||
       (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Use the maximum size */
    UA_UInt16 keySizeBits = 4096;
    /* Default to 1 year */
    UA_UInt16 expiresInDays = 365;
    /* Key type: 0 = RSA (default), 1 = EC */
    int keyTypeEC = 0;
    UA_String eccCurve = UA_STRING_STATIC("prime256v1");

    if(params) {
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
        if(keySizeBitsValue)
            keySizeBits = *keySizeBitsValue;

        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
        if(expiresInDaysValue)
            expiresInDays = *expiresInDaysValue;

        const UA_String *keyTypeValue = (const UA_String *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "key-type"), &UA_TYPES[UA_TYPES_STRING]);
        if(keyTypeValue && uaStringEqualsCI(keyTypeValue, "ec"))
            keyTypeEC = 1;

        const UA_String *eccCurveValue = (const UA_String *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "ecc-curve"), &UA_TYPES[UA_TYPES_STRING]);
        if(eccCurveValue && eccCurveValue->length > 0)
            eccCurve = *eccCurveValue;
    }

    UA_ByteString_init(outPrivateKey);
    UA_ByteString_init(outCertificate);

    UA_String fullAltSubj = UA_STRING_NULL;
    UA_Int32 serial = 1;

    /** \TODO: Seed Random generator
    * See: (https://www.openssl.org/docs/man1.1.0/man3/RAND_add.html) */
    BIO *memCert = NULL;
    BIO *memPKey = NULL;

    UA_StatusCode errRet = UA_STATUSCODE_GOOD;

    X509 *x509 = X509_new();

#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
    EVP_PKEY *pkey = NULL;
    if(keyTypeEC) {
        pkey = UA_ECC_Generate_Key(logger, &eccCurve);
        if(!pkey) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Create Certificate: ECC key generation failed.");
            errRet = UA_STATUSCODE_BADINTERNALERROR;
            X509_free(x509);
            return errRet;
        }
    } else {
        pkey = UA_RSA_Generate_Key(keySizeBits);
    }
    if((pkey == NULL) || (x509 == NULL)) {
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }    
#else
    if(keyTypeEC) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: ECC key generation requires OpenSSL >= 3.0");
        X509_free(x509);
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }
    BIGNUM *exponent = BN_new();
    EVP_PKEY *pkey = EVP_PKEY_new();
    RSA *rsa = RSA_new();
    if(!pkey || !x509 || !exponent || !rsa) {
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL,
                "Create Certificate: Generating RSA key. This may take a while.");

    if(BN_set_word(exponent, RSA_F4) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting RSA exponent failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(RSA_generate_key_ex(rsa, (int) keySizeBits, exponent, NULL) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Generating RSA key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Assign RSA key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }
    /* rsa will be freed by pkey */
    rsa = NULL;

#endif  /* end of OPENSSL_VERSION_NUMBER >= 0x30000000L */

    /* x509v3 has version 2
     * (https://www.openssl.org/docs/man1.1.0/man3/X509_set_version.html) */
    if(X509_set_version(x509, 2) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting version failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(ASN1_INTEGER_set(X509_get_serialNumber(x509), serial) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting serial number failed.");
        /* Only memory errors are possible */
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    if(X509_gmtime_adj(X509_get_notBefore(x509), 0) == NULL) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'not before' failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(X509_time_adj_ex(X509_get_notAfter(x509), (int)expiresInDays, 0, NULL) ==
       NULL) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'not before' failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(X509_set_pubkey(x509, pkey) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting publik key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    X509_NAME *name = X509_get_subject_name(x509);
    if(name == NULL) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Getting name failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    for(UA_UInt32 iSubject = 0; iSubject < subjectSize; ++iSubject) {
        UA_Int32 sep = UA_String_chr(&subject[iSubject], '=');
        char field[16];
        if(sep == -1 || sep == 0 ||
            ((size_t) sep == (subject[iSubject].length - 1)) || sep >= 15) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Create Certificate: Subject must contain one '=' with "
                         "content before and after.");
            errRet = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
        memcpy(field, subject[iSubject].data, (size_t) sep);
        field[sep] = 0;
        UA_Byte* pData = &subject[iSubject].data[sep + 1];
        if(X509_NAME_add_entry_by_txt(
               name, field, MBSTRING_ASC,
               (const unsigned char *)pData,
               (int) subject[iSubject].length - (int) sep - 1, -1, 0) != 1) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Create Certificate: Setting subject failed.");
            errRet = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
    }
    /* Self signed, so issuer == subject */
    if(X509_set_issuer_name(x509, name) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting name failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_basic_constraints, "CA:FALSE");
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Basic Constraints' failed.");
        goto cleanup;
    }

    /* See https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 for
     * possible values. ECC certificates need keyAgreement for ECDH. */
    const char *keyUsageStr = keyTypeEC
        ? "digitalSignature,nonRepudiation,keyAgreement,keyCertSign"
        : "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyCertSign";
    errRet = add_x509V3ext(logger, x509, NID_key_usage, (char*)(uintptr_t)keyUsageStr);
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Key Usage' failed.");
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_ext_key_usage, "serverAuth,clientAuth");
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Extended Key Usage' failed.");
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_subject_key_identifier, "hash");
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Subject Key Identifier' failed.");
        goto cleanup;
    }

    errRet = join_string_with_sep(subjectAltName, subjectAltNameSize, ',', &fullAltSubj);
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Joining altSubject failed.");
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_subject_alt_name, (char*) fullAltSubj.data);
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Subject Alternative Name' failed.");
        goto cleanup;
    }

    /* Select the digest for signing.
     * EdDSA (Ed25519/Ed448): pass NULL (intrinsic hash).
     * ECDSA P-384 / brainpoolP384r1: SHA-384.
     * Everything else (RSA, P-256, brainpoolP256r1): SHA-256. */
    const EVP_MD *signMd = EVP_sha256();
    if(keyTypeEC) {
        if(uaStringEqualsCI(&eccCurve, "ed25519") ||
           uaStringEqualsCI(&eccCurve, "ed448"))
            signMd = NULL; /* EdDSA uses intrinsic hash */
        else if(uaStringEqualsCI(&eccCurve, "secp384r1") ||
                uaStringEqualsCI(&eccCurve, "nistp384") ||
                uaStringEqualsCI(&eccCurve, "brainpoolp384r1"))
            signMd = EVP_sha384();
    }

    if(X509_sign(x509, pkey, signMd) == 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Signing failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    switch(certFormat) {
        case UA_CERTIFICATEFORMAT_DER: {
            unsigned char *p;
            /* Private Key */
            /* get length */
            outPrivateKey->length = (size_t)i2d_PrivateKey(pkey, NULL);
            if((int)outPrivateKey->length <= 0) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Create private DER key failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
            /* allocate buffer */
            UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
            memset(outPrivateKey->data, 0, outPrivateKey->length);
            p = outPrivateKey->data;
            i2d_PrivateKey(pkey, &p);

            /* Certificate */
            /* get length */
            outCertificate->length = (size_t)i2d_X509(x509, NULL);
            if((int)outCertificate->length <= 0) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Create DER-certificate failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
            /* allocate buffer */
            UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
            memset(outCertificate->data, 0, outCertificate->length);
            p = outCertificate->data;
            i2d_X509(x509, &p);
            break;
        }
        case UA_CERTIFICATEFORMAT_PEM: {
            /* Private Key */
            memPKey = BIO_new(BIO_s_mem());
            if(!memPKey) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Allocate Membuffer for PKey failed.");
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
                goto cleanup;
            }

            if(PEM_write_bio_PrivateKey(memPKey, pkey, NULL, NULL, 0, 0, NULL) != 1) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Generate PEM-PrivateKey failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }

            UA_ByteString tmpPem = UA_BYTESTRING_NULL;
            tmpPem.length = (size_t) BIO_get_mem_data(memPKey, &tmpPem.data);
            errRet = UA_ByteString_copy(&tmpPem, outPrivateKey);
            if(errRet != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Copy PEM PKey failed.");
                goto cleanup;
            }

            /* Certificate */
            memCert = BIO_new(BIO_s_mem());
            if(!memCert) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Allocate Membuffer for Cert failed.");
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
                goto cleanup;
            }

            if(PEM_write_bio_X509(memCert, x509) != 1) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Generate PEM-Certifcate failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }

            tmpPem.length = (size_t) BIO_get_mem_data(memCert, &tmpPem.data);
            errRet = UA_ByteString_copy(&tmpPem, outCertificate);
            if(errRet != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Copy PEM Certificate failed.");
                goto cleanup;
            }
            break;
        }
    }

cleanup:
    UA_String_clear(&fullAltSubj);
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
    RSA_free(rsa);
    BN_free(exponent);    
#endif
    X509_free(x509);
    EVP_PKEY_free(pkey);
    BIO_free(memCert);
    BIO_free(memPKey);
    return errRet;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/certificategroup.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>


#define SHA1_DIGEST_LENGTH 20

/* Configuration parameters */

#define MEMORYCERTSTORE_PARAMETERSSIZE 2
#define MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE 0
#define MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE 1

static const struct {
    UA_QualifiedName name;
    const UA_DataType *type;
    UA_Boolean required;
} MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMETERSSIZE] = {
    {{0, UA_STRING_STATIC("maxTrustListSize")}, &UA_TYPES[UA_TYPES_UINT16], false},
    {{0, UA_STRING_STATIC("maxRejectedListSize")}, &UA_TYPES[UA_TYPES_STRING], false}
};

struct MemoryCertStore;
typedef struct MemoryCertStore MemoryCertStore;

struct MemoryCertStore {
    UA_TrustListDataType trustList;
    size_t rejectedCertificatesSize;
    UA_ByteString *rejectedCertificates;

    UA_UInt32 maxTrustListSize;
    UA_UInt32 maxRejectedListSize;

    UA_Boolean reloadRequired;

    STACK_OF(X509) *trustedCertificates;
    STACK_OF(X509) *issuerCertificates;
    STACK_OF(X509_CRL) *crls;
};

static UA_Boolean
openSSLCheckCA(X509 *cert);

static UA_StatusCode
MemoryCertStore_removeFromTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    context->reloadRequired = true;
    return UA_TrustListDataType_remove(trustList, &context->trustList);
}

static UA_StatusCode
MemoryCertStore_getTrustList(UA_CertificateGroup *certGroup, UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    return UA_TrustListDataType_copy(&context->trustList, trustList);
}

static UA_StatusCode
MemoryCertStore_setTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    context->reloadRequired = true;
    /* Remove the section of the trust list that needs to be reset, while keeping the remaining parts intact */
    return UA_TrustListDataType_set(trustList, &context->trustList);
}

static UA_StatusCode
MemoryCertStore_addToTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
    /* Check parameter */
    if(certGroup == NULL || trustList == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(&context->trustList) + UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    context->reloadRequired = true;
    return UA_TrustListDataType_add(trustList, &context->trustList);
}

static UA_StatusCode
MemoryCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **rejectedList, size_t *rejectedListSize) {
    /* Check parameter */
    if(certGroup == NULL || rejectedList == NULL || rejectedListSize == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    UA_StatusCode retval = UA_Array_copy(context->rejectedCertificates, context->rejectedCertificatesSize,
                                         (void**)rejectedList, &UA_TYPES[UA_TYPES_BYTESTRING]);

    if(retval == UA_STATUSCODE_GOOD)
        *rejectedListSize = context->rejectedCertificatesSize;

    return retval;
}

static UA_StatusCode
openSSLCheckCrlMatch(X509 *cert, X509_CRL *crl) {
    X509_NAME *certSubject = X509_get_subject_name(cert);
    if(!certSubject)
        return UA_STATUSCODE_BADINTERNALERROR;

    X509_NAME *crlIssuer = X509_CRL_get_issuer(crl);
    if(!crlIssuer) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(X509_NAME_cmp(certSubject, crlIssuer) == 0)
        return UA_STATUSCODE_GOOD;

    return UA_STATUSCODE_BADNOMATCH;
}

static UA_StatusCode
openSSLFindCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
                const UA_ByteString *crlList, const size_t crlListSize,
                UA_ByteString **crls, size_t *crlsSize) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(!cert)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Check if the certificate is a CA certificate.
     * Only a CA certificate can have a CRL. */
    if(!openSSLCheckCA(cert)) {
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                       "The certificate is not a CA certificate and therefore does not have a CRL.");
        X509_free(cert);
        return UA_STATUSCODE_GOOD;
    }

    UA_Boolean foundMatch = false;
    for(size_t i = 0; i < crlListSize; i++) {
        X509_CRL *crl = UA_OpenSSL_LoadCrl(&crlList[i]);
        if(!crl) {
            X509_free(cert);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        retval = openSSLCheckCrlMatch(cert, crl);
        X509_CRL_free(crl);
        if(retval != UA_STATUSCODE_GOOD) {
            continue;
        }

        /* Continue the search, as a certificate may be associated with multiple CRLs. */
        foundMatch = true;
        retval = UA_Array_appendCopy((void **)crls, crlsSize, &crlList[i],
                                 &UA_TYPES[UA_TYPES_BYTESTRING]);
        if(retval != UA_STATUSCODE_GOOD) {
            X509_free(cert);
            return retval;
        }
    }
    X509_free(cert);
    if(!foundMatch)
        return UA_STATUSCODE_BADNOMATCH;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
MemoryCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
                                   const UA_Boolean isTrusted, UA_ByteString **crls,
                                   size_t *crlsSize) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL || crls == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;

    if(isTrusted) {
        return openSSLFindCrls(certGroup, certificate,
                               context->trustList.trustedCrls,
                               context->trustList.trustedCrlsSize, crls,
                               crlsSize);
    }
    return openSSLFindCrls(certGroup, certificate,
                           context->trustList.issuerCrls,
                           context->trustList.issuerCrlsSize, crls,
                           crlsSize);
}

static UA_StatusCode
MemoryCertStore_addToRejectedList(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;

    /* check duplicate certificate */
    for(size_t i = 0; i < context->rejectedCertificatesSize; i++) {
        if(UA_ByteString_equal(certificate, &context->rejectedCertificates[i]))
            return UA_STATUSCODE_GOOD; /* certificate already exist */
    }

    /* Store rejected certificate */
    if(context->maxRejectedListSize == 0 || context->rejectedCertificatesSize < context->maxRejectedListSize) {
        return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
                                   certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
    }
    UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
    context->rejectedCertificates = NULL;
    context->rejectedCertificatesSize = 0;
    return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
                               certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
}

static void
MemoryCertStore_clear(UA_CertificateGroup *certGroup) {
    /* check parameter */
    if(certGroup == NULL) {
        return;
    }

    UA_NodeId_clear(&certGroup->certificateGroupId);

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context) {
        UA_TrustListDataType_clear(&context->trustList);

        UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
        context->rejectedCertificates = NULL;
        context->rejectedCertificatesSize = 0;

        sk_X509_pop_free(context->trustedCertificates, X509_free);
        sk_X509_pop_free(context->issuerCertificates, X509_free);
        sk_X509_CRL_pop_free(context->crls, X509_CRL_free);

        UA_free(context);
        certGroup->context = NULL;
    }
}

static UA_StatusCode
reloadCertificates(UA_CertificateGroup *certGroup) {
    /* Check parameter */
    if(certGroup == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;

    sk_X509_pop_free(context->trustedCertificates, X509_free);
    context->trustedCertificates = sk_X509_new_null();
    if(context->trustedCertificates == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    for(size_t i = 0; i < context->trustList.trustedCertificatesSize; i++) {
        X509 *cert = UA_OpenSSL_LoadCertificate(&context->trustList.trustedCertificates[i], EVP_PKEY_NONE);
        if(cert == NULL)
            return UA_STATUSCODE_BADINTERNALERROR;
        sk_X509_push(context->trustedCertificates, cert);
    }

    sk_X509_pop_free(context->issuerCertificates, X509_free);
    context->issuerCertificates = sk_X509_new_null();
    if(context->issuerCertificates == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    for(size_t i = 0; i < context->trustList.issuerCertificatesSize; i++) {
        X509 *cert = UA_OpenSSL_LoadCertificate(&context->trustList.issuerCertificates[i], EVP_PKEY_NONE);
        if(cert == NULL)
            return UA_STATUSCODE_BADINTERNALERROR;
        sk_X509_push(context->issuerCertificates, cert);
    }

    sk_X509_CRL_pop_free(context->crls, X509_CRL_free);
    context->crls = sk_X509_CRL_new_null();
    if(context->crls == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    for(size_t i = 0; i < context->trustList.trustedCrlsSize; i++) {
        X509_CRL * crl = NULL;
        BIO * bio = NULL;

        bio = BIO_new_mem_buf((void *)context->trustList.trustedCrls[i].data,
                              (int)context->trustList.trustedCrls[i].length);
        /* Try to load DER encoded CRL */
        crl = d2i_X509_CRL_bio(bio, NULL);
        if(crl == NULL) {
            /* Try to load PEM encoded CRL */
            (void)BIO_reset(bio);
            crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
        }
        BIO_free(bio);

        if(crl == NULL)
            return UA_STATUSCODE_BADINTERNALERROR;
        sk_X509_CRL_push(context->crls, crl);
    }
    for(size_t i = 0; i < context->trustList.issuerCrlsSize; i++) {
        X509_CRL * crl = NULL;
        BIO * bio = NULL;

        bio = BIO_new_mem_buf((void *)context->trustList.issuerCrls[i].data,
                              (int)context->trustList.issuerCrls[i].length);
        /* Try to load DER encoded Issuer CRL */
        crl = d2i_X509_CRL_bio(bio, NULL);
        if(crl == NULL) {
            /* Try to load PEM encoded Issuer CRL */
            (void)BIO_reset(bio);
            crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
        }
        BIO_free(bio);

        if(crl == NULL)
            return UA_STATUSCODE_BADINTERNALERROR;
        sk_X509_CRL_push(context->crls, crl);
    }

    return UA_STATUSCODE_GOOD;
}

/* Find binary substring. Taken and adjusted from
 * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */

static const unsigned char *
bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
    /* find first occurrence of c in char s[] for length l*/
    for(; l > 0; ++s, --l) {
        if(*s == ch)
            return s;
    }
    return NULL;
}

static const unsigned char *
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
    /* find first occurrence of s2[] in s1[] for length l1*/
    const unsigned char *ss1 = s1;
    const unsigned char *ss2 = s2;
    /* handle special case */
    if(l1 == 0)
        return NULL;
    if(l2 == 0)
        return s1;

    /* match prefix */
    for(; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
            (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {

        /* match rest of prefix */
        const unsigned char *sc1, *sc2;
        for(sc1 = s1, sc2 = s2; ;)
            if(++sc2 >= ss2+l2)
                return s1;
            else if (*++sc1 != *sc2)
                break;
    }
    return NULL;
}

static const unsigned char openssl_PEM_PRE[28] = "-----BEGIN CERTIFICATE-----";

/* Extract the leaf certificate from a bytestring that may contain an entire chain */
static X509 *
openSSLLoadLeafCertificate(UA_ByteString cert, size_t *offset) {
    if(cert.length <= *offset)
        return NULL;
    cert.length -= *offset;
    cert.data += *offset;

    /* Detect DER encoding. Extract the encoding length and cut. */
    if(cert.length >= 4 && cert.data[0] == 0x30 && cert.data[1] == 0x82) {
        /* The certificate length is encoded after the magic bytes */
        size_t certLen = 4; /* Magic numbers + length bytes */
        certLen += (size_t)(((uint16_t)cert.data[2]) << 8);
        certLen += cert.data[3];
        if(certLen > cert.length)
            return NULL;
        cert.length = certLen;
        *offset += certLen;
        const UA_Byte *dataPtr = cert.data;
        return d2i_X509(NULL, &dataPtr, (long)cert.length);
    }

    /* Assume PEM encoding. Detect multiple certificates and cut. */
    if(cert.length > 27 * 4) {
        const unsigned char *match =
            UA_Bstrstr(openssl_PEM_PRE, 27, &cert.data[27*2], cert.length - (27*2));
        if(match)
            cert.length = (uintptr_t)(match - cert.data);
    }
    *offset += cert.length;

    BIO *bio = BIO_new_mem_buf((void *) cert.data, (int)cert.length);
    X509 *result = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    BIO_free(bio);
    return result;
}

/* The bytestring might contain an entire certificate chain. The first
 * stack-element is the leaf certificate itself. The remaining ones are
 * potential issuer certificates. */
static STACK_OF(X509) *
openSSLLoadCertificateStack(const UA_ByteString cert) {
    size_t offset = 0;
    X509 *x509 = NULL;
    STACK_OF(X509) *result = sk_X509_new_null();
    if(!result)
        return NULL;
    while((x509 = openSSLLoadLeafCertificate(cert, &offset))) {
        sk_X509_push(result, x509);
    }
    return result;
}

/* Return the first matching issuer candidate AFTER prev */
static X509 *
openSSLFindNextIssuer(MemoryCertStore *ctx, STACK_OF(X509) *stack, X509 *x509, X509 *prev) {
    /* First check issuers from the stack - provided in the same bytestring as
     * the certificate. This can also return x509 itself. */
    X509_NAME *in = X509_get_issuer_name(x509);
    do {
        int size = sk_X509_num(stack);
        for(int i = 0; i < size; i++) {
            X509 *candidate = sk_X509_value(stack, i);
            if(prev) {
                if(prev == candidate)
                    prev = NULL; /* This was the last issuer we tried to verify */
                continue;
            }
            /* This checks subject/issuer name and the key usage of the issuer.
             * It does not verify the validity period and if the issuer key was
             * used for the signature. We check that afterwards. */
            if(X509_NAME_cmp(in, X509_get_subject_name(candidate)) == 0)
                return candidate;
        }
        /* Switch from the stack that came with the cert to the issuer list and
         * then to the trust list. */
        if(stack == ctx->trustedCertificates)
            stack = NULL;
        else if(stack == ctx->issuerCertificates)
            stack = ctx->trustedCertificates;
        else
            stack = ctx->issuerCertificates;
    } while(stack);
    return NULL;
}

/* Is the certificate a CA? */
static UA_Boolean
openSSLCheckCA(X509 *cert) {
    uint32_t flags = X509_get_extension_flags(cert);
    /* The basic constraints must be set with the CA flag true */
    if(!(flags & EXFLAG_CA))
        return false;

    /* The Key Usage extension must be set */
    if(!(flags & EXFLAG_KUSAGE))
        return false;

    /* The Key Usage must include cert signing and CRL issuing */
    uint32_t usage = X509_get_key_usage(cert);
    if(!(usage & KU_KEY_CERT_SIGN) || !(usage & KU_CRL_SIGN))
        return false;

    return true;
}

static UA_StatusCode
openSSLCheckRevoked(UA_CertificateGroup *cg, MemoryCertStore *ctx, X509 *cert) {
    const ASN1_INTEGER *sn = X509_get0_serialNumber(cert);
    const X509_NAME *in = X509_get_issuer_name(cert);
    int size = sk_X509_CRL_num(ctx->crls);

    if(size == 0) {
        UA_LOG_WARNING(cg->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                       "Zero revocation lists have been loaded. "
                       "This seems intentional - omitting the check.");
        return UA_STATUSCODE_GOOD;
    }

    /* Loop over the crl and match the Issuer Name */
    UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
    for(int i = 0; i < size; i++) {
        /* The crl contains a list of serial numbers from the same issuer */
        X509_CRL *crl = sk_X509_CRL_value(ctx->crls, i);
        if(X509_NAME_cmp(in, X509_CRL_get_issuer(crl)) != 0)
            continue;
        STACK_OF(X509_REVOKED) *rs = X509_CRL_get_REVOKED(crl);
        int rsize = sk_X509_REVOKED_num(rs);
        for(int j = 0; j < rsize; j++) {
            X509_REVOKED *r = sk_X509_REVOKED_value(rs, j);
            if(ASN1_INTEGER_cmp(sn, X509_REVOKED_get0_serialNumber(r)) == 0)
                return UA_STATUSCODE_BADCERTIFICATEREVOKED;
        }
        res = UA_STATUSCODE_GOOD; /* There was at least one crl that did not revoke (so far) */
    }
    return res;
}

#define UA_OPENSSL_MAX_CHAIN_LENGTH 10

static UA_StatusCode
openSSL_verifyChain(UA_CertificateGroup *cg, MemoryCertStore *ctx, STACK_OF(X509) *stack,
                    X509 **old_issuers, X509 *cert, int depth) {
    /* Maxiumum chain length */
    if(depth == UA_OPENSSL_MAX_CHAIN_LENGTH)
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;

    /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is
     * returned only if all possible chains are incomplete. */
    X509 *issuer = NULL;
    UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    while(ret != UA_STATUSCODE_GOOD) {
        /* Find the issuer. We jump back here to find a different path if a
         * subsequent check fails. */
        issuer = openSSLFindNextIssuer(ctx, stack, cert, issuer);
        if(!issuer)
            break;

        /* Verification Step: Certificate Usage
         * Can the issuer act as CA? Omit for self-signed leaf certificates. */
        if((depth > 0 || issuer != cert) && !openSSLCheckCA(issuer)) {
            ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED;
            continue;
        }

        /* Verification Step: Signature */
        int opensslRet = X509_verify(cert, X509_get0_pubkey(issuer));
        if(opensslRet == -1) {
            return UA_STATUSCODE_BADCERTIFICATEINVALID; /* Ill-formed signature */
        } else if(opensslRet == 0) {
            ret = UA_STATUSCODE_BADCERTIFICATEINVALID;  /* Wrong issuer, try again */
            continue;
        }

        /* The certificate is self-signed. We have arrived at the top of the
         * chain. We check whether the certificate is trusted below. This is the
         * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED.
         * This signals that the chain is complete (but can be still
         * untrusted).
         *
         * Break here as we have reached the end of the chain. Omit the
         * Revocation Check for self-signed certificates. */
        if(cert == issuer || X509_cmp(cert, issuer) == 0) {
            ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
            break;
        }

        /* Verification Step: Revocation Check */
        ret = openSSLCheckRevoked(cg, ctx, cert);
        if(depth > 0) {
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED)
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED;
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN)
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
        }
        if(ret != UA_STATUSCODE_GOOD)
            continue;

        /* Detect (endless) loops of issuers. The last one can be skipped by the
         * check for self-signed just before. */
        for(int i = 0; i < depth; i++) {
            if(old_issuers[i] == issuer)
                return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
        }
        old_issuers[depth] = issuer;

        /* We have found the issuer certificate used for the signature. Recurse
         * to the next certificate in the chain (verify the current issuer). */
        ret = openSSL_verifyChain(cg, ctx, stack, old_issuers, issuer, depth + 1);
    }

    /* Is the certificate in the trust list? If yes, then we are done. */
    if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) {
        for(int i = 0; i < sk_X509_num(ctx->trustedCertificates); i++) {
            if(X509_cmp(cert, sk_X509_value(ctx->trustedCertificates, i)) == 0) {
                ret = UA_STATUSCODE_GOOD;
                break;
            }
        }
    }

    if (ret == UA_STATUSCODE_GOOD) {
        /* Verification Step: Validity Period */
        ASN1_TIME *notBefore = X509_get_notBefore(cert);
        ASN1_TIME *notAfter = X509_get_notAfter(cert);
        if(X509_cmp_current_time(notBefore) != -1 || X509_cmp_current_time(notAfter) != 1)
            return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID :
                UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID;
    }

    return ret;
}

/* This follows Part 6, 6.1.3 Determining if a Certificate is trusted.
 * It defines a sequence of steps for certificate verification. */
static UA_StatusCode
verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
    /* Check parameter */
    if(certGroup == NULL || certGroup->context == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
    if(context->reloadRequired) {
        ret = reloadCertificates(certGroup);
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
        context->reloadRequired = false;
    }

    /* Verification Step: Certificate Structure */
    STACK_OF(X509) *stack = openSSLLoadCertificateStack(*certificate);
    if(!stack || sk_X509_num(stack) < 1) {
        sk_X509_pop_free(stack, X509_free);
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    }

    /* Verification Step: Certificate Usage
     * Check whether the certificate is a User certificate or a CA certificate.
     * Refer the test case CTT/Security/Security Certificate Validation/029.js
     * for more details. */
    X509 *leaf = sk_X509_value(stack, 0);
    if(openSSLCheckCA(leaf)) {
        sk_X509_pop_free(stack, X509_free);
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    }

    /* These steps are performed outside of this method.
     * Because we need the server or client context.
     * - Security Policy
     * - Host Name
     * - URI */

    /* Verification Step: Build Certificate Chain
     * We perform the checks for each certificate inside. */
    X509 *old_issuers[UA_OPENSSL_MAX_CHAIN_LENGTH];
    ret = openSSL_verifyChain(certGroup, context, stack, old_issuers, leaf, 0);
    sk_X509_pop_free(stack, X509_free);
    return ret;
}

static UA_StatusCode
MemoryCertStore_verifyCertificate(UA_CertificateGroup *certGroup,
                                  const UA_ByteString *certificate) {
    /* Check parameter */
    if(certGroup == NULL || certificate == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = verifyCertificate(certGroup, certificate);
    if(retval != UA_STATUSCODE_GOOD) {
        if(MemoryCertStore_addToRejectedList(certGroup, certificate) != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                           "Could not append certificate to rejected list");
        }
    }
    return retval;
}

UA_StatusCode
UA_CertificateGroup_Memorystore(UA_CertificateGroup *certGroup,
                                UA_NodeId *certificateGroupId,
                                const UA_TrustListDataType *trustList,
                                const UA_Logger *logger,
                                const UA_KeyValueMap *params) {

    if(certGroup == NULL || certificateGroupId == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Clear if the plugin is already initialized */
    if(certGroup->clear)
        certGroup->clear(certGroup);

    UA_NodeId_copy(certificateGroupId, &certGroup->certificateGroupId);
    certGroup->logging = logger;

    certGroup->getTrustList = MemoryCertStore_getTrustList;
    certGroup->setTrustList = MemoryCertStore_setTrustList;
    certGroup->addToTrustList = MemoryCertStore_addToTrustList;
    certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
    certGroup->getRejectedList = MemoryCertStore_getRejectedList;
    certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
    certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
    certGroup->clear = MemoryCertStore_clear;

    /* Set PKI Store context data */
    MemoryCertStore *context = (MemoryCertStore *)UA_calloc(1, sizeof(MemoryCertStore));
    if(!context) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }
    certGroup->context = context;
    /* Default values */
    context->maxTrustListSize = 65535;
    context->maxRejectedListSize = 100;

    if(params) {
        const UA_UInt32 *maxTrustListSize = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);

        const UA_UInt32 *maxRejectedListSize = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);

        if(maxTrustListSize) {
            context->maxTrustListSize = *maxTrustListSize;
        }

        if(maxRejectedListSize) {
            context->maxRejectedListSize = *maxRejectedListSize;
        }
    }

    UA_TrustListDataType_add(trustList, &context->trustList);
    reloadCertificates(certGroup);

    return UA_STATUSCODE_GOOD;

cleanup:
    certGroup->clear(certGroup);
    return retval;
}

UA_StatusCode
UA_CertificateUtils_verifyApplicationUri(const UA_ByteString *certificate,
                                         const UA_String *applicationURI) {
    const unsigned char *pData = certificate->data;
    if(!pData)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(!certificateX509)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    GENERAL_NAMES *pNames = (GENERAL_NAMES *)
        X509_get_ext_d2i(certificateX509, NID_subject_alt_name, NULL, NULL);
    if(!pNames) {
        X509_free(certificateX509);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    UA_String subjectURI = UA_STRING_NULL;
    for(int i = 0; i < sk_GENERAL_NAME_num(pNames); i++) {
        GENERAL_NAME *value = sk_GENERAL_NAME_value(pNames, i);
        if(value->type == GEN_URI) {
            subjectURI.length = (size_t) (value->d.ia5->length);
            subjectURI.data = (UA_Byte*)UA_malloc(subjectURI.length);
            if(!subjectURI.data) {
                X509_free(certificateX509);
                sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
                return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            }
            (void)memcpy(subjectURI.data, value->d.ia5->data, subjectURI.length);
            break;
        }
    }

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(UA_Bstrstr(subjectURI.data, subjectURI.length,
                  applicationURI->data, applicationURI->length) == NULL)
        ret = UA_STATUSCODE_BADCERTIFICATEURIINVALID;

    X509_free(certificateX509);
    sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
    UA_String_clear(&subjectURI);
    return ret;
}

UA_StatusCode
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
                                      UA_DateTime *expiryDateTime) {
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(!x509)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Get the certificate Expiry date */
    ASN1_TIME *not_after = X509_get_notAfter(x509);

    struct tm dtTime;
    ASN1_TIME_to_tm(not_after, &dtTime);
    X509_free(x509);

    struct musl_tm dateTime;
    memset(&dateTime, 0, sizeof(struct musl_tm));
    dateTime.tm_year = dtTime.tm_year;
    dateTime.tm_mon = dtTime.tm_mon;
    dateTime.tm_mday = dtTime.tm_mday;
    dateTime.tm_hour = dtTime.tm_hour;
    dateTime.tm_min = dtTime.tm_min;
    dateTime.tm_sec = dtTime.tm_sec;

    long long sec_epoch = musl_tm_to_secs(&dateTime);
    *expiryDateTime = UA_DATETIME_UNIX_EPOCH;
    *expiryDateTime += sec_epoch * UA_DATETIME_SEC;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
                                   UA_String *subjectName) {
    X509_NAME *sn = NULL;
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    X509_CRL *x509_crl = NULL;

    if(x509) {
        sn = X509_get_subject_name(x509);
    } else {
        x509_crl = UA_OpenSSL_LoadCrl(certificate);
        if(!x509_crl)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        sn = X509_CRL_get_issuer(x509_crl);
    }

    char buf[1024];
    *subjectName = UA_STRING_ALLOC(X509_NAME_oneline(sn, buf, 1024));

    if(x509)
        X509_free(x509);
    if(x509_crl)
        X509_CRL_free(x509_crl);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
                                  UA_String *thumbprint) {
    if(certificate == NULL || thumbprint->length != (SHA1_DIGEST_LENGTH * 2))
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char digest[SHA1_DIGEST_LENGTH];
    unsigned int digestLen;

    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(cert) {
        if(X509_digest(cert, EVP_sha1(), digest, &digestLen) != 1) {
            X509_free(cert);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        X509_free(cert);
    } else {
        X509_CRL *crl = UA_OpenSSL_LoadCrl(certificate);
        if(!crl)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        if(X509_CRL_digest(crl, EVP_sha1(), digest, &digestLen) != 1) {
            X509_CRL_free(crl);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        X509_CRL_free(crl);
    }

    UA_String thumb = UA_STRING_NULL;
    thumb.length = (SHA1_DIGEST_LENGTH * 2) + 1;
    thumb.data = (UA_Byte*)malloc(sizeof(UA_Byte) * thumb.length);

    /* Create a string containing a hex representation */
    char *p = (char*)thumb.data;
    for(size_t i = 0; i < digestLen; i++) {
        p += sprintf(p, "%.2X", digest[i]);
    }

    memcpy(thumbprint->data, thumb.data, thumbprint->length);
    free(thumb.data);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
                               size_t *keySize){
    if(certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(!cert)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    EVP_PKEY *pkey = X509_get_pubkey(cert);
    if(!pkey) {
        X509_free(cert);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
        *keySize = EVP_PKEY_get_size(pkey) * 8;
#else
        *keySize =  RSA_size(get_pkey_rsa(pkey)) * 8;
#endif
    } else if(EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) {
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
        *keySize = EVP_PKEY_get_size(pkey) * 8;
#else
        *keySize =  ECDSA_size(EVP_PKEY_get0_EC_KEY(pkey)) * 8;
#endif
    } else {
        EVP_PKEY_free(pkey);
        X509_free(cert);
        return UA_STATUSCODE_BADINTERNALERROR; /* Unsupported key type */
    }

    EVP_PKEY_free(pkey);
    X509_free(cert);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
                                      const UA_ByteString *certificate2) {
    if(certificate1 == NULL || certificate2 == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    BIO *dataBio1 = BIO_new_mem_buf(certificate1->data, certificate1->length);
    if(!dataBio1)
        return UA_STATUSCODE_BADINTERNALERROR;

    BIO *dataBio2 = BIO_new_mem_buf(certificate2->data, certificate2->length);
    if(!dataBio2) {
        BIO_free(dataBio1);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    X509 *cert1 = NULL;
    X509 *cert2 = NULL;
    X509_REQ *csr1 = NULL;
    X509_REQ *csr2 = NULL;
    /* Try to read the certificate as PEM first */
    cert1 = PEM_read_bio_X509(dataBio1, NULL, 0, NULL);
    if(!cert1) {
        /* If PEM read fails, reset BIO and try reading as DER */
        (void)BIO_reset(dataBio1);
        cert1 = d2i_X509_bio(dataBio1, NULL);
    }
    /* Try to read as a csr */
    if(!cert1) {
        (void)BIO_reset(dataBio1);
        csr1 = PEM_read_bio_X509_REQ(dataBio1, NULL, 0, NULL);
        if(!csr1) {
            (void)BIO_reset(dataBio1);
            csr1 = d2i_X509_REQ_bio(dataBio1, NULL);
        }
    }
    if(!cert1 && !csr1) {
        BIO_free(dataBio1);
        BIO_free(dataBio2);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    cert2 = PEM_read_bio_X509(dataBio2, NULL, 0, NULL);
    if(!cert2) {
        /* If PEM read fails, reset BIO and try reading as DER */
        (void)BIO_reset(dataBio2);
        cert2 = d2i_X509_bio(dataBio2, NULL);
    }
    /* Try to load as a csr */
    if(!cert2) {
        (void)BIO_reset(dataBio2);
        csr2 = PEM_read_bio_X509_REQ(dataBio2, NULL, 0, NULL);
        if(!csr2) {
            (void)BIO_reset(dataBio2);
            csr2 = d2i_X509_REQ_bio(dataBio2, NULL);
        }
    }
    if(!cert2 && !csr2) {
        X509_free(cert1);
        X509_REQ_free(csr1);
        BIO_free(dataBio1);
        BIO_free(dataBio2);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    BIO_free(dataBio1);
    BIO_free(dataBio2);

    EVP_PKEY *pkey1 = cert1 ? X509_get_pubkey(cert1) : X509_REQ_get_pubkey(csr1);
    EVP_PKEY *pkey2 = cert2 ? X509_get_pubkey(cert2) : X509_REQ_get_pubkey(csr2);

    X509_free(cert1);
    X509_free(cert2);
    X509_REQ_free(csr1);
    X509_REQ_free(csr2);

    if(!pkey1 || !pkey2) {
        EVP_PKEY_free(pkey1);
        EVP_PKEY_free(pkey2);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
    int isEqual = EVP_PKEY_eq(pkey1, pkey2);
    if(isEqual == 0)
        retval = UA_STATUSCODE_BADNOMATCH;
    if(isEqual < 0)
        retval = UA_STATUSCODE_BADINTERNALERROR;
#else
    int isEqual = EVP_PKEY_cmp(pkey1, pkey2);
    if(isEqual == 0)
        retval = UA_STATUSCODE_BADNOMATCH;
    if(isEqual < 0)
        retval = UA_STATUSCODE_BADINTERNALERROR;
#endif

    EVP_PKEY_free(pkey1);
    EVP_PKEY_free(pkey2);

    return retval;
}

UA_StatusCode
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
                                 const UA_ByteString *privateKey) {
    if(certificate == NULL || privateKey == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(!cert)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    EVP_PKEY *pkey = UA_OpenSSL_LoadPrivateKey(privateKey);
    if(!pkey) {
        X509_free(cert);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    /* Verify if the private key matches the public key in the certificate */
    if(X509_check_private_key(cert, pkey) != 1) {
        X509_free(cert);
        EVP_PKEY_free(pkey);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    X509_free(cert);
    EVP_PKEY_free(pkey);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
    if(certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
    if(!certificateX509)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = openSSLCheckCA(certificateX509) ?
        UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOMATCH;
    X509_free(certificateX509);
    return retval;
}

static int
privateKeyPasswordCallback(char *buf, int size, int rwflag, void *userdata) {
    (void) rwflag;
    UA_ByteString *pw = (UA_ByteString*)userdata;
    if(pw->length <= (size_t)size)
        memcpy(buf, pw->data, pw->length);
    return (int)pw->length;
}

UA_StatusCode
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
                                      const UA_ByteString password,
                                      UA_ByteString *outDerKey) {
    if(!outDerKey)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(privateKey.length == 0) {
        *outDerKey = UA_BYTESTRING_NULL;
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    EVP_PKEY *pkey = NULL;
    const unsigned char * in = privateKey.data;

    /* Check if input is already in DER format */
    pkey = d2i_AutoPrivateKey(NULL, &in, privateKey.length);
    if(pkey != NULL) {
        EVP_PKEY_free(pkey);
        return UA_ByteString_copy(&privateKey, outDerKey);
    }

    /* Decrypt */
    BIO *bio = BIO_new_mem_buf((void*)privateKey.data, (int)privateKey.length);
    pkey = PEM_read_bio_PrivateKey(bio, NULL,
                                             privateKeyPasswordCallback,
                                             (void*)(uintptr_t)&password);
    BIO_free(bio);
    if(!pkey)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Write DER encoded, allocates the new memory */
    unsigned char *data = NULL;
    const int numBytes = i2d_PrivateKey(pkey, &data);
    EVP_PKEY_free(pkey);
    if(!data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Copy to the data to outDerKey
     * Passing the data pointer directly causes a heap corruption on Windows
     * when outDerKey is cleared.
     */
    UA_ByteString temp = UA_BYTESTRING_NULL;
    temp.data = data;
    temp.length = (size_t)numBytes;
    const UA_StatusCode success = UA_ByteString_copy(&temp, outDerKey);
    /* OPENSSL_clear_free() is not supported by the LibreSSL version in the CI */
    OPENSSL_cleanse(data, numBytes);
    OPENSSL_free(data);
    return success;
}

#endif
